WebSocket strumienie i wydarzenia
TL; DR
Strumień pracy = zaufany kanał (WSS) + podsumowane przesunięcia + zdarzenia idempotentne + ścisłe limity i ciśnienie wsteczne. Zrób: uwierzytelnianie JWT, autoryzacja tematów, bicie serca, seq/offset + wznowienie, co najmniej raz + deadup. Dla skali - shading użytkownik/lokator, lepki routing, i kolejka (Kafka/NATS/Redis Streams) jako źródło prawdy.
1) Sprawy biznesowe iGaming (co naprawdę strumieniujemy)
Saldo/limity: chwilowe zmiany salda, limity RG, blokady.
Zakłady/rundy/wyniki: potwierdzenie, stan, obliczanie wygranych.
Turnieje/liderki: pozycje, timery, wydarzenia nagród.
Płatności: status wypłaty/zwrotu, flagi KYC/AML - takie jak powiadomienia (i krytyka pozostaje w hakach internetowych REST +).
Wydarzenia serwisowe: wiadomości czatu, banery push, statusy sesji, konserwacja.
2) Protokół i połączenie
Tylko WSS (TLS 1. 2+/1. 3). Maksymalnie 1 aktywne połączenie na domyślne urządzenie/sesję.
Ping/Pong: klient wysyła 'ping' every 20-30 sekund, czas odpowiedzi wynosi 10 sekund. Serwer zrzuca połączenie w 3 kolejnych terminach.
Kompresja: 'permessage-deflate', limit wielkości ramki (na przykład ≤ 64 KB).
Format ładunku: JSON dla zewnętrznych, Protobuf/MsgPack dla wewnętrznych/mobilnych.
3) Uwierzytelnianie i autoryzacja
Uścisk dłoni JWT w zapytaniu/nagłówku („Sec-WebSocket-Protocol ”/„ Authorization”), TTL token krótki (≤ 15 min), odświeżony przez out-of-band (REST).
Oświadczenia najemcy: „sub”, „najemca”, „scopes”, „risk _ flag”.
ACL do tematów/kanałów: subskrybowanie tylko dozwolonych 'tematów' (na przykład: 'user: {id}', 'turniej: {id}', 'gra: {table}').
Ponowne utworzenie połączenia po wygaśnięciu tokena: „miękkie okno” 60 s.
4) Model subskrypcji
Klient wysyła polecenia po połączeniu:json
{ "op":"subscribe", "topics":["user:123", "tournament:456"], "resume_from":"1748852201:987654" }
{ "op":"unsubscribe", "topics":["tournament:456"] }
'resume _ from' - offset (patrz § 5), jeśli klient ponownie się połączy.
Serwer odpowiada ack/nack, nieudane ACL są w 'nack' z 'reason'.
5) Gwarancje dostawy i podsumowanie
Cel: co najmniej raz na kanał + idempotencja w kliencie.
Każde wydarzenie ma monotonne 'seq' within 'part' (zwykle użytkownik/pokój) oraz globalne 'event _ id' dla deduplication.
Przy ponownym połączeniu klient wysyła 'resume _ from' = ostatni potwierdzony 'seq' (lub 'offset' brokera). Serwer ładuje brakujące zdarzenia z „źródła prawdy” (Kafka/NATS/Redis Streams).
Jeśli opóźnienie przekroczy retencję (na przykład 24 godziny), serwer wysyła 'migawkę' stanu i nowy 'seq'.
- Przechowywanie 'last _ seq '/' event _ id' w trwałej pamięci masowej (IndexedDB/Keychain).
- Dedup by 'event _ id', pomiń zdarzenia z' seq ≤ last_seq', wykryć otwory (luka) → auto- 'resync' żądanie migawki.
6) Schemat wiadomości (koperta)
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” - taksonomia domeny (patrz słownik zdarzeń).
PII/PCI - wykluczyć/maskę na poziomie bramy.
7) Wsparcie, kwoty i ochrona przed „drogimi” klientami
Serwer → Klient: per-connection send-queue z przesuwanym oknem. Pełna - resetowanie subskrypcji tematów „hałaśliwych” lub odłączenie od kodu „1013 ”/„ policy _ violation”.
Klient → Serwer: limity 'subscribe/unsubscribe' (na przykład, ≤ 10/sek), limit listy tematów (≤ 50), minimalny przedział resubskrypcji.
Limity stawek przez IP/najemcę/klucz. Anomalie → tymczasowe blokowanie.
Priorytet: najważniejsze wydarzenia (równowaga, limity RG) - kolejka priorytetowa.
8) Ochrona i bezpieczeństwo
WAF/bot profil na dłoni uścisk końcowy, Pochodzenie dozwolona lista.
mTLS pomiędzy bramą krawędziową a węzłami strumieniowymi.
Ochrona DoS: pliki cookie SYN na L4, limity liczby otwartych WS/utrzymać żywy okres.
Anty-replay: 'timestamp' w opcjonalnym podpisie ładunkowym (dla partnerów) z ważnym oknem 5 min.
Izolacja lokatora: fizyczne/logiczne odcienie, klucze/żetony na lokatora.
9) Architektura transportu
Brama (krawędź): terminal TLS, authN/Z, kwoty, routing na stronę.
Węzły strumieniowe: bezpaństwowcy o lepkiej trasie przez 'hash (user_id)% N'.
Broker wydarzeń: Kafka/NATS/Redis Streams - źródło prawdy i bufor powtórki.
State-service: przechowuje migawki (saldo, pozycje w turnieju).
Wielobranżowe: aktywa; GSLB według najbliższego regionu; home-region jest ustalony przy logowaniu; z feiler - „zimne” podsumowanie z innego regionu.
10) Porządek, spójność, idempotencja
Zamawianie jest gwarantowane wewnątrz strony (użytkownik/pokój), a nie na całym świecie.
Spójność: wydarzenie może nastąpić przed odpowiedzią REST; UX musi być w stanie żyć w stanie pośrednim (optymistyczne uzgadnianie UI +).
Idempotence: ponowne przetwarzanie 'event _ id' nie zmienia stanu klienta.
11) Błędy, ponowne połączenie i burze
Kody końcowe: '1000' (normalne), '1008' (zasady), '1011' (wewnętrzne), '1013' (przeciążenie serwera).
Klient wykładniczy backoff + jitter: 1s, 2s, 4s... maks. 30 s.
Podczas ponownego połączenia masy („thundering stado”) - serwer daje 'retry _ after' i 'siwy' odpowiedzi z poleceniem użycia SSE fallback tylko do odczytu.
12) Gotówka i migawki
Każda subskrypcja może rozpocząć się migawką bieżącego stanu, a następnie strumieniem zdarzeń diff.
Versioning i kompatybilność schematu data _ version (rozszerzenie pola nie łamie klientów).
13) Obserwowalność i SLO
Metryka:- Połączenia: aktywne, ustalone/sec, dystrybucja według lokatora/regionu.
- Dostawa: p50/p95 opóźnienia od brokera do klienta, drop-rate, resend-rate.
- Niezawodność: udział udanych CV bez migawki, detektor szczeliny.
- Błędy: 4xx/5xx na uścisk dłoni, kody zamykające, limity.
- Ładowanie: RPS poleceń „subskrybuj”, rozmiar kolejki, procesor/NET.
- Ustanowienie WS p95 ≤ 500 ms (w obrębie regionu).
- Zdarzenie opóźnienia od końca do końca p95 ≤ 300 ms (przegroda użytkownika).
- Powrót do sukcesu ≥ 99%, utrata wiadomości = 0 (w najmniejszym czasie).
- Punkt końcowy strumienia wzrostowego ≥ 99. 95%.
14) Schemat i zarządzanie wersją
Słownik wydarzeń z właścicielami, przykładami i semantyką.
Ewolucja „miękka”: dodawanie tylko pól opcjonalnych; deletion - po okresie '@ deprecated'.
Testy kontraktowe na SDK klienta, lintery na JSON Schema/Protobuf.
15) Playbooks incydent (osadzone we wspólnym playbook)
Wzrost opóźnień: przełączyć strony na węzły zapasowe, zwiększyć rozmiar partii w brokerze, umożliwić priorytetowe określenie najważniejszych wydarzeń.
Ponowne podłączenie burzy: aktywowanie 'retry _ after', tymczasowe podnoszenie limitów uścisku dłoni, włączanie awaryjnego SSE.
Wyciek tokenu: rotacja JWKS, cofnięcie dotkniętych żetonów, przymusowe ponowne połączenie z ponownym autem.
Utrata strony brokera: przeniesienie do trybu migawki, powtórzenie po odzyskaniu.
16) Mini specyfikacja API (uproszczona)
Uścisk dłoni (HTTP GET → WS):
GET /ws? tenant=acme&client=web
Headers:
Authorization: Bearer <JWT>
X-Trace-Id: <uuid>
Polecenia klienta:
json
{ "op":"subscribe", "topics":["user:123"], "resume_from":"1748852201:42" }
{ "op":"unsubscribe", "topics":["user:123"] }
{ "op":"ping", "ts":"2025-11-03T12:34:56Z" }
Odpowiedzi serwera:
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) Lista kontrolna UAT
- Podsumowanie z offsetu po 1/10/60 minut przestoju klienta.
- Dedup: redeliveria tego samego 'event _ id' nie zmienia stanu.
- Detektor szczeliny → automatyczne 'migawki' i wyrównanie.
- Kwoty i obciążenie zwrotne: załadowany klient otrzymuje odłączenie od zasad.
- Multiregion: region awaryjny przy jednoczesnym utrzymaniu offsetu.
- Bezpieczeństwo: Token rocker wygasł przez JWT, próbując subskrybować poza ACL.
- Saldo RG/event jest przed/po REST - UI poprawnie „szwy”.
18) Częste błędy
Brak 'seq/offset' i odnowienie - stracić wydarzenia i zaufanie.
Mieszanie krytycznych poleceń płatniczych w mutacjach WS - użyj REST.
Brak szkód/kwot - „zawieszone” połączenia i lawina pamięci.
Globalne porządki są drogie i niepotrzebne; dość porządku na przyjęciu.
Logowanie PII w wydarzeniach - naruszenie prywatności i PCI/RODO.
Brak słownika wydarzeń i wersioning - klienci się rozpadają.
Podsumowanie
Strumienie WebSocket dają reaktywne sygnały UX i operacyjne, jeśli są zbudowane jako podsumowany, chroniony i ograniczony kanał: WSS + mTLS/JWT, ACL na tematy, seq/offset + wznowić, co najmniej raz z deduplication, backpressure/quotas, broker jako źródło prawdy, obserwowalność i SLO. Tak więc strumienie pozostają szybkie dla użytkownika i zarządzalne dla platformy - bez kompromisów w zakresie bezpieczeństwa i pieniędzy.