Skip to content
Language:hu Author:Laborci Gergely
realtime

WebSocket skálázása és lassú kliensek kezelése

Célok

A lecke végére el tudod magyarázni, miért kötődik egy kapcsolat egy szerverpéldányhoz, hogyan jut el az esemény a megfelelő példányhoz, és mit lehet tenni a lassú klienssel.

Miért kell?

Egy WebSocket-kapcsolat fennállása alatt egy konkrét szerverpéldányhoz kötődik. Több példánynál ezért tudni kell, melyik kapcsolathoz melyik eseményt kell továbbítani. A terheléselosztás (7.7) új kapcsolatot helyez el; a már nyitott kapcsolatot nem mozgatja át észrevétlenül másik folyamatba.

Helyi és megosztott állapot

A kapcsolatobjektum és a küldési puffer a fogadó példány memóriájában van. A felhasználó azonossága, a feliratkozások és a folytatási pont egy része lehet tartós vagy megosztott, de a megosztás nem jelenti, hogy egy másik folyamat ugyanazt a kapcsolatot használja. Az üzleti eseményforrás és a példányok közé ezért közvetítő kerül (8.1: pub/sub), amely minden példánynak eljuttatja az eseményt, az pedig a saját kapcsolataira osztja szét.

flowchart TB
  C1["Kliens 1"] --> L["Terheléselosztó"]
  C2["Kliens 2"] --> L
  L --> W1["WebSocket-példány 1"]
  L --> W2["WebSocket-példány 2"]
  E["Üzleti eseményforrás"] --> B["Közös pub/sub"]
  B --> W1
  B --> W2
  W1 -->|"saját kapcsolatai"| C1
  W2 -->|"saját kapcsolatai"| C2

Sok példánynál csatorna- vagy célalapú elosztás célszerű, hogy ne minden példány kapjon minden eseményt. A közös pub/sub nem feltétlenül tartós visszajátszási napló (8.1): a két feladatot külön tervezzük.

Sticky session és kiesés

Az NGINX dokumentációja szerint az IP-hash módszer ugyanazon kliens kéréseit azonos kiszolgálóhoz tereli (sticky). Ez azoknál a megoldásoknál lehet hasznos, ahol több kérés tartozik össze (például egy könyvtár tartalék long polling szállítása). A már nyitott WebSocket ugyanúgy a saját példányán marad. A stickiness nem helyettesíti a közös eseményterítést és a szerverkiesés utáni resyncet (10.3).

Ha a példány kiesik, a kliens másikhoz csatlakozik. Ennek újra ellenőriznie kell a jogosultságot, és helyre kell állítania a feliratkozást (10.5). A csak a helyi memóriában tárolt üzleti állapot elvész, ezért a tartós parancseredmény ne éljen kizárólag a kapcsolat memóriájában.

Lassú kliens és puffer

A szerver gyorsabban termelhet eseményt, mint ahogy a kliens fogadja. Az MDN szerint a böngészői WebSocket interfész nem támogatja a backpressure-t: ha az üzenetek gyorsabban érkeznek, mint ahogy az alkalmazás feldolgozza őket, a memória megtelhet, vagy a processzor 100%-ra terhelődhet. A WebSocketStream ezt a Streams API-val kezeli, de az MDN szerint nem szabványos, és csak egy böngészőmotor támogatja. A szerver oldalán a küldési puffer korlátlan növelése memóriakimerüléshez vezet; a nem kiküldött bájtok, az üzenetek száma és a legöregebb adat kora a kapcsolatszámnál jobb jelzés.

Aktuális állapotnál több frissítés összevonható a legújabbra. Fontos üzleti eseményeknél tartós napló és későbbi folytatás kell (8.1). Túl lassú kliens bontása indokolt lehet, ha a protokoll egyértelműen megmondja a helyreállítás módját (10.3).

Kivezetés

Leállításkor a példány ne fogadjon új kapcsolatot; a meglévőket korlátozott időn belül zárhatja le (1001 „going away” kód, RFC 6455), vagy újracsatlakozási jelzéssel terelheti másik példányra. A tömeges bontás reconnect-hullámot okoz, ezért fokozatosság és jitter szükséges. A proxykonfigurációnak támogatnia kell a kapcsolatfelépítést és az elvárt tétlenségi időt; a köztes pufferelés, a rövid időkorlát és a maximális kapcsolatszám eltérő hibákat okozhat.

Jellemzők

Szempont Skálázott WebSocket
Irány Kétirányú, példányok közt közvetítővel
Kezdeményező Kliens (kapcsolat), bármelyik fél (üzenet)
Kapcsolat tartóssága Példányhoz kötött
Késleltetés Plusz egy ugrás a közvetítőn
Terhelés Kapcsolat × üzenetütem × fan-out
Hibatűrés Példánykiesésnél resync; lassú kliensnél összevonás vagy bontás
Mikor jó? Sok párhuzamos élő kliens megosztott eseményforrással
Mikor nem? Ha a kliensszám kicsi és az igény ritka (polling/SSE egyszerűbb)

Gyakori tévhitek

Állítás Pontosítás
„A terheléselosztó áthelyezi a nyitott kapcsolatot.” Csak új kapcsolatot helyez el.
„A sticky session megoldja a skálázást.” Nem oldja meg az események szétosztását és a kiesést.
„A böngészői WebSocket automatikusan lassít, ha a fogadó lassú.” Nincs backpressure (MDN).
„Több kapcsolat = több terhelés, egyenes arányban.” Az üzenetütem és a fan-out számít.

Röviden

  • A kapcsolat példányhoz kötött; az eseményeket közvetítő juttatja el a megfelelő példányhoz.
  • Helyi, megosztott és tartós állapotot külön kell kezelni.
  • A böngészői WebSocketnek nincs backpressure-je; a lassú kliensnél összevonás, napló vagy bontás kell.
  • Kivezetéskor fokozatos bontás és jitter véd a reconnect-hullám ellen.

Ellenőrző kérdések

  1. Miért nem elég a terheléselosztó a WebSocket skálázásához?
  2. Mely állapot lokális, megosztott és tartós egy többpéldányos rendszerben?
  3. Mit tehetsz, ha a kliens lassabban fogad, mint ahogy a szerver termel?

Források

Prerequisites (4)

  • WebSocket
  • terheléselosztás
  • publish–subscribe
  • backpressure

Teaches (2)

  • WebSocket-skálázás
  • lassú kliens