WebSocketストリームとイベント
TL;DR(ドクター)
Work stream=trusted channel (WSS)+summarized offsets+idempotent events+strict limits and backpressure。Do: JWT認証、トピックの承認、ハートビート、seq/offset+resume-token、最低1回+deadup。スケールの場合-ユーザー/テナントのシャーディング、スティッキールーティング、キュー(Kafka/NATS/Redis Streams)を真実のソースとして使用します。
1) iGamingビジネスケース(私たちが実際にストリーミングするもの)
バランス/限界:バランスの瞬間的な変化、RG限界、ロック。
ベット/ラウンド/結果:確認、ステータス、賞金の計算。
トーナメント/リーダーボード:ポジション、タイマー、賞品イベント。
支払い:支払い/払い戻しステータス、KYC/AMLフラグ-通知など(および批判はREST+webhookに残ります)。
サービスイベント:チャットメッセージ、プッシュバナー、セッションステータス、メンテナンス。
2)議定書および関係
WSSのみ(TLS 1。2+/1.3).デフォルトのデバイス/セッションごとに最大1つのアクティブ接続。
Ping/Pong:クライアントは'ping' every 20-30秒を送信し、応答タイムアウトは10秒です。サーバーは3つの連続したタイムアウトで接続をドロップします。
圧縮:'permessage-deflate'、フレームサイズ制限(例:≤ 64 KB)。
ペイロード形式:外部用JSON、内部/モバイル用Protobuf/MsgPack。
3)認証と認証
クエリ/ヘッダー('Sec-WebSocket-Protocol'/'Authorization')、 TTLトークンショート(≤ 15分)、帯域外(REST)による更新。
テナントスコープのクレーム:'sub'、 'tenant'、 'scopes'、 'risk_flags'。
topics/channelsへのACL:許可された'トピック'のみを購読する(例:'user: {id}'、 'tournament: {id}'、 'game: {table}')。
トークンの有効期限が切れたときの接続の再作成:「ソフトウィンドウ」60秒。
4)サブスクリプションモデル
クライアントはconnect後にコマンドを送信します:json
{ "op":"subscribe", "topics":["user:123", "tournament:456"], "resume_from":"1748852201:987654" }
{ "op":"unsubscribe", "topics":["tournament:456"] }
'resume_from'-クライアントが再接続する場合、オフセット(第5章を参照)。
サーバはack/nackで応答し、失敗したACLは'reason'で'nack'にある。
5)配達保証および要約
目的:チャネルごとの少なくとも1回+クライアントのidempotency。
各イベントには"part'(通常はユーザー/ルーム)とグローバルな"event_id"で単調な"seq"があります。
再接続すると、クライアントは'resume_from'=最後に確認された'seq'(ブローカーの'offset')を送信します。サーバーは、「source of truth」 (Kafka/NATS/Redis Streams)から欠落したイベントをロードします。
遅延が保持時間(例えば24時間)を超えた場合、サーバーはステートの'スナップショット'と新しい'seq'を送信します。
- 耐久性のあるストレージ(IndexedDB/Keychain)に'last_seq'/'event_id'を格納します。
- 'event_id'でデダップし、'seq ≤ last_seq'でイベントをスキップし、穴(ギャップ)→自動'再同期'スナップショットリクエストを検出します。
6)メッセージスキーム(封筒)
json
{
"ts": "2025-11-03T12:34:56. 789Z",
"topic": "user:123",
"seq": "1748852201:987654", // partition:offset
"event_id": "01HF..", // UUID/KSUID
"type": "balance. updated",
"data": { "currency":"EUR", "delta"--5. 00, "balance":125. 37 },
"trace_id": "4e3f.., "//for correlation
"signature": "base64 (hmac (...)) "//optional for partners
}
'type'-ドメインタクソノミ(イベント辞書を参照)。
PII/PCI-ゲートウェイレベルで除外/マスク。
7)「高価な」顧客に対する背圧、クォータおよび保護
サーバー→クライアント:スライディングウィンドウを持つ接続ごとのsend-queue。完全-「noisy」トピックにサブスクリプションをリセットするか、コード'1013'/'policy_violation'で切断します。
クライアント→サーバー:'subscribe/unsubscribe'の制限(例えば、≤ 10/sec)、トピック一覧の制限(≤ 50)、最低再登録間隔。
IP/テナント/キーによるレート制限。異常→一時的なブロック。
優先順位:重要なイベント(バランス、RG制限)-優先順位キュー。
8)保護および安全
ハンドシェイクエンドポイントのWAF/botプロファイル、Origin allowed list。
エッジゲートウェイとストリームノード間のmTLS。
DoS保護:L4上のSYNクッキー、開いているWS/keep-alive間隔の数の制限。
アンチリプレイ:オプションのペイロード署名の'タイムスタンプ'(パートナー用)で、有効なウィンドウが5分です。
テナント分離:物理的/論理的なシャーディング、テナントごとのキー/トークン。
9)交通機関の建築
ゲートウェイ(エッジ):TLSターミナル、authN/Z、クォータ、パーティーごとのルーティング。
ストリームノード:'hash (user_id)% N'によるスティッキールートを持つステートレスワーカー。
イベントブローカー:Kafka/NATS/Redis Streams-真実とリプレイバッファのソース。
ステートサービス:スナップショット(バランス、トーナメントのポジション)を保存します。
マルチリージョン:アセットアセット;最寄りの地域によるGSLB;ホーム地域はログイン時に固定されています。feiler-別の地域からの「冷たい」要約。
10)順序、一貫性、idempotency
注文は、パーティー内で保証されています(ユーザー/ルーム)、グローバルではありません。
一貫性:イベントはREST応答の前に来るかもしれません。UXは中間状態(楽観的なUI+和解)で生活できる必要があります。
Idempotence: 'event_id'の再処理はクライアントの状態を変更しません。
11)エラー、再接続および嵐
閉じるコード:'1000'(通常)、'1008'(ポリシー)、'1011'(内部)、'1013'(サーバーの過負荷)。
クライアント指数関数バックオフ+ジッタ:1s、 2s、 4s……最高の30代。
大量再接続中("thundering herd')-サーバーは'retry_after'と'gray'応答を与え、読み取り専用にSSEフォールバックを使用するプロンプトを表示します。
12)現金とスナップショット
各サブスクリプションは、現在の状態のスナップショットから開始し、diffイベントのストリームから開始できます。
data_versionスキーマのバージョン管理と互換性(フィールド拡張はクライアントを壊すことはありません)。
13)観察可能性およびSLO
メトリクス:- 接続:アクティブ、確立/秒、テナント/地域別の配布。
- 配達:ブローカーからクライアントへのp50/p95遅延、ドロップレート、再送料。
- 信頼性:スナップショット、ギャップ検出器なしで成功した履歴書の共有。
- エラー:4xx/5xxハンドシェイク、クローズコード、リミットヒット。
- ロード:'subscribe'コマンド、キューサイズ、CPU/NETのRPS。
- WS p95 ≤ 500ミリ秒(地域内)の確立。
- エンドツーエンドのレイテンシーイベントp95 ≤ 300ミリ秒(ユーザーパーティション)。
- 成功を再開≥ 99%、メッセージ損失=0(少なくとも1回)。
- アップタイムストリームエンドポイント≥ 99。95%.
14)スキーマとバージョン管理
所有者、例、意味論を含むイベントの辞書。
「ソフト」の進化:オプションのフィールドのみを追加します。削除-'@deprecated'期間後。
クライアントSDK、 JSON Schema/Protobuf上のLinterに対する契約テスト。
15)インシデントプレイブック(共有プレイブックに埋め込む)
レイテンシーの増加:当事者をバックアップノードに切り替え、ブローカーでのバッチのサイズを増やし、重要なイベントの優先順位付けを可能にします。
stormの再接続:'retry_after'を有効化し、一時的にハンドシェイク制限を上げ、SSEフォールバックを有効にします。
トークン漏洩:JWKSローテーション、影響を受けるトークンの失効、再認証で再接続を強制。
ブローカーパーティーの損失:スナップショットモードへの転送、回復後のリプレイ。
16) APIの小型指定(簡略化される)
ハンドシェイク(HTTP GET→WS):
GET /ws? tenant=acme&client=web
Headers:
Authorization: Bearer <JWT>
X-Trace-Id: <uuid>
クライアントコマンド:
json
{ "op":"subscribe", "topics":["user:123"], "resume_from":"1748852201:42" }
{ "op":"unsubscribe", "topics":["user:123"] }
{ "op":"ping", "ts":"2025-11-03T12:34:56Z" }
サーバーの応答:
json
{ "op":"ack", "id":"subscribe:user:123" }
{ "op":"event", "topic":"user:123", "seq":"1748852201:43", "type":"balance. updated", "data":{...} }
{ "op":"snapshot", "topic":"user:123", "seq":"1748852201:42", "state":{...} }
{ "op":"error", "code":"acl_denied", "reason":"no access to topic tournament:456" }
{ "op":"pong", "ts":"..." }
17) UATチェックリスト
- クライアントのダウンタイムの1/10/60分後のオフセットからの概要。
- Dedup:同じ'event_id'の再配達はステートを変更しません。
- ギャップディテクタ→自動'スナップショット'とアライメント。
- クォータとbackpressure:ロードされたクライアントはpolicy-disconnectを受け取ります。
- Multiregion:オフセットを維持しながらフェイルオーバー領域。
- セキュリティ:トークンロッカーはJWTによって期限切れになり、ACL外で購読しようとしています。
- RG/イベントバランスはRESTの前後にあります-UIは正しく「ステッチ」します。
18)頻繁なエラー
いいえ'seq/offset'と更新-イベントと信頼を失う。
WS変異における重要な支払いコマンドの混在-RESTを使用します。
背圧/クォータの欠如-「中断」接続とメモリの雪崩。
グローバルな秩序は高価で不要です。パーティーで十分な順番だ。
PIIログインイベント-プライバシー違反とPCI/GDPR。
イベントとバージョン管理の辞書がない-クライアントは故障します。
概要
WSS+mTLS/JWT、トピックに関するACL、 seq/offset+resume、 deduplication、 backpressure/quotas、 brokerをソースとして構築すると、WebSocketストリームはリアクティブなUXと運用信号を提供します真実、観測可能性およびSLOの。したがって、ストリームはユーザーにとって高速であり、プラットフォームにとって管理可能です。セキュリティとお金の妥協はありません。