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
Miért nem elég a terheléselosztó a WebSocket skálázásához?
Mely állapot lokális, megosztott és tartós egy többpéldányos rendszerben?
Mit tehetsz, ha a kliens lassabban fogad, mint ahogy a szerver termel?
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.
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
WebSocketinterfé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. AWebSocketStreamezt 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
Gyakori tévhitek
Röviden
Ellenőrző kérdések
Források
WebSocketStream.