WebSocket strims et événements
TL; DR
Flux de travail = Flux fiable (WSS) + offsets résumés + événements idempotent + limites strictes et backpressure. Faites : authentification JWT, autorisation pour les tops, heartbeats, seq/offset + resume-token, at-least-once + dedup. Pour l'échelle - Charding par user/tenant, sticky-rowting, et la file d'attente (Kafka/NATS/Redis Streams) comme source de vérité.
1) Affaires affaires iGaming (ce qui est vraiment streaming)
Équilibre/limites : changements instantanés du solde, limites RG, verrous.
Paris/rondes/résultats : confirmation, statut, calcul des gains.
Tournois/leaders : positions, minuteries, événements de prix.
Paiements : statut payout/refund, drapeaux KYC/AML - comme notifications (et la critique reste dans REST + webhooks).
Événements de service : messages de chat, bannières push, statuts de session, maintenance.
2) Protocole et connexion
WSS uniquement (TLS 1. 2+/1. 3). Maximum 1 connexion active par périphérique/session par défaut.
Ping/Pong : client shlet 'ping' toutes les 20 à 30 s, délai de réponse 10 s. Le serveur réinitialise la connexion à 3 temps consécutifs.
Compression : 'permessage-deflate', limite de taille du cadre (par exemple, ≤ 64 Ko).
Format de charge utile : JSON pour externe, Protobuf/MsgPack pour interne/mobile.
3) Authentification et autorisation
Handshake avec JWT dans query/header (« Sec-WebSocket-Protocol »/« Autorité »), TTL token court (≤ 15 min), refresh par out-of-band (REST).
Tenant-scoped claims: `sub`, `tenant`, `scopes`, `risk_flags`.
ACL sur les tops/canaux : abonnement uniquement aux 'topic' autorisés (par exemple : 'user : {id}', 'tournament : {id}', 'game : {table}').
Réapprovisionnement de la connexion à l'expiration du jeton : « fenêtre molle » 60 s.
4) Modèle d'abonnement
Le client envoie les commandes après connect :json
{ "op":"subscribe", "topics":["user:123", "tournament:456"], "resume_from":"1748852201:987654" }
{ "op":"unsubscribe", "topics":["tournament:456"] }
resume _ from - offset (voir § 5) si le client restaure la connexion.
Le serveur répond ack/nack, l'ACL non exécutée est dans 'nack' avec 'reason'.
5) Garanties de livraison et résumé
Objectif : at-least-once par canal + idempotence chez le client.
Chaque événement a un 'seq' monotone dans le cadre d'un « lot » (user/room en général) et un 'event _ id'global pour le dédup.
En ré-connect, le client passe 'resume _ from' = le dernier 'seq'confirmé (ou 'offset' du courtier). Le serveur rattrape les événements manqués à partir de la « source de vérité » (Kafka/NATS/Redis Streams).
Si lag dépasse retaction (par exemple 24 h) - le serveur envoie un état 'snapshot' et un nouveau 'seq'.
- Stocker 'last _ seq '/' event _ id' dans le stockage durable (IndexedDB/Keychain).
- Dédup par 'event _ id', ignorer les événements de' seq ≤ last_seq', détecter les trous (gap) → auto-resync 'de la requête snapshot.
6) Schéma de message (envelope)
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 » est une taxonomie de domaine (voir dictionnaire des événements).
PII/PCI - supprimer/masquer au niveau de la passerelle.
7) Backpressure, quotas et protection contre les clients « chers »
Serveur → Client : per-connection send-queue avec « fenêtre glissante ». Surchargé - réinitialiser les abonnements aux tops « bruyants » ou disconnect avec le code '1013 '/' policy _ violence'.
Client → Server : Limites pour 'subscribe/unsubscribe' (par exemple, ≤ 10/s), limitation de la liste des tops (≤ 50), intervalle minimum de réabonnement.
Limites de taux par IP/tenant/clé. Anomalies → blocage temporaire.
Priorité : les événements vitaux (bilan, limites RG) sont la file d'attente prioritaire.
8) Protection et sécurité
Profil WAF/bot sur le handshake-endpoint, liste des Origin autorisés.
mTLS entre la passerelle edge et les nœuds de stream.
Protection DoS : SYN-cookies sur L4, limites sur le nombre de WS ouverts/intervalle keep-alive.
Anti-replay : 'timestamp' dans la signature de charge utile facultative (pour les partenaires) avec une fenêtre valide de 5 min.
Isolation des locataires : Chardonnages physiques/logiques, clés/jetons per-tenant.
9) L'architecture des transports
Passerelle (edge) : Terminate TLS, authN/Z, quotas, routage par lot.
Noeuds Stream : stateless-workers avec sticky-routing par 'hash (user_id) % N'.
Courtier d'événements : Kafka/NATS/Redis Streams est une source de vérité et un tampon de repli.
Service d'État : stocke les snapshots (balance, positions dans le tournoi).
Multiregion : actif-actif ; GSLB pour la région la plus proche ; la région d'origine est fixée au login ; dans le feilover - « froid » m d'une autre région.
10) Ordre, cohérence, idempotence
L'ordre est garanti dans le lot (user/room), pas globalement.
Cohérence : un événement peut arriver avant la réponse REST ; L'UX doit être capable de vivre avec un état intermédiaire (optimistic UI + reconciliation).
Idempotence : Le traitement répété de 'event _ id' ne change pas l'état du client.
11) Erreurs, reconnect et « tempête »
Codes de fermeture : '1000' (normal), '1008' (politique), '1011' (interne), '1013' (server overload).
Client exponentiel backoff + jitter : 1s, 2s, 4s... max 30s.
Lors des reconfigurations massives ("thundering herd'), le serveur donne 'retry _ after' et des réponses" grises "avec un conseil pour utiliser SSE fallback pour lire.
12) Cache et snapshots
Chaque abonnement peut commencer par un snapshot de l'état actuel, puis par un flux d'événements diff.
La versionation du schéma 'data _ version' et la compatibilité (l'extension des champs ne brise pas les clients).
13) Observabilité et SLO
Métriques :- Connexions : actif, installé/s, distribution par locataire/région.
- Livraison : p50/p95 retards du courtier au client, drop-rate, resend-rate.
- Fiabilité : proportion de succès sans snapshot, détecteur de gap.
- Erreurs : 4xx/5xx sur le handshake, codes de fermeture, hits de limite.
- Charge : RPS des commandes 'subscribe', taille des files d'attente, CPU/NET.
- Établissement de WS p95 ≤ 500 ms (à l'intérieur de la région).
- Événement de fin de fin de latence p95 ≤ 300 ms (user-partition).
- Resume success ≥ 99%, message loss = 0 (по at-least-once).
- Uptime stream-endpoint ≥ 99. 95%.
14) Gestion des schémas et des versions
Dictionnaire d'événements avec propriétaires, exemples et sémantique.
Évolution « douce » : uniquement l'ajout de champs optionnels ; suppression - après '@ deprecated' période.
Tests contractuels contre les SDK clients, linters sur JSON Schema/Protobuf.
15) Pleybooks incidents (incorporer dans votre pleybook partagé)
Croissance de latitude : changer les lots en nœuds de secours, augmenter la taille de batch chez le courtier, activer la hiérarchisation des événements vitaux.
Tempête de reconfiguration : activer 'retry _ after', augmenter temporairement les limites du handshake, activer le SSE-follback.
Fuite de tokens : rotation JWKS, rappel des tokens touchés, reconnect forcé avec re-auth.
Perte du lot du courtier : mise en mode snapshot, repli après récupération.
16) Mini-spécification API (simplifiée)
Handshake (HTTP GET → WS):
GET /ws? tenant=acme&client=web
Headers:
Authorization: Bearer <JWT>
X-Trace-Id: <uuid>
Commandes du client :
json
{ "op":"subscribe", "topics":["user:123"], "resume_from":"1748852201:42" }
{ "op":"unsubscribe", "topics":["user:123"] }
{ "op":"ping", "ts":"2025-11-03T12:34:56Z" }
Réponses du serveur :
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) chèque UAT
- M de l'offset après 1/10/60 minutes de downtime du client.
- Dedup : refaire le même 'event _ id'ne change pas d'état.
- Le détecteur de gap → automatique 'snapshot' et l'alignement.
- Quotas et backpressure : le client chargé reçoit policy-disconnect.
- Multiregion : Fauteur de région avec conservation offset.
- Security : jeton rocker expiré par JWT, tentative d'abonnement en dehors de l'ACL.
- RG/l'équilibre de l'événement arrive avant/après REST - UI correctement « coudre ».
18) Erreurs fréquentes
Pas de « seq/offset » et de reprise - nous perdons les événements et la confiance.
Mélanger les commandes de paiement critiques dans les mutations WS - utiliser REST.
L'absence de backpressure/quotas est une connexion « suspendue » et une avalanche de mémoire.
L'ordre mondial est coûteux et inutile ; l'ordre dans le parti suffit.
L'enregistrement PII dans les événements - violations de la vie privée et PCI/GDPR.
Absence de dictionnaire d'événements et de versioning - les clients se cassent.
Résumé
Les sockets WebSocket donnent des UX réactifs et des signaux opérationnels s'ils sont construits comme un canal résumé, sécurisé et limité : WSS + mTLS/JWT, ACL sur les tops, seq/offset + resume, at-least-once, backpressure/quotas, courtier comme source de vérité, observabilité et SLO. C'est ainsi que les strips restent rapides pour l'utilisateur et gérables pour la plate-forme - sans compromis sur la sécurité et l'argent.