Požiadavka prichádza do zadania takmer vždy v rovnakej podobe: „chceme, aby sa to aktualizovalo naživo, bez obnovovania stránky“. Znie to ako detail — veď ide len o to, aby číslo na obrazovke nezaostávalo za realitou. V skutočnosti je to jedno z rozhodnutí, ktoré najviac mení architektúru aplikácie, náklady na prevádzku aj to, čo všetko musí tím po spustení sledovať.
Rozdiel je principiálny. Bežná webová aplikácia odpovedá na otázky: príde požiadavka, vráti sa odpoveď, spojenie sa zavrie a server na klienta zabudne. Real-time webová aplikácia si musí s každým otvoreným prehliadačom udržiavať vzťah — vedieť, kto je pripojený, čo ho zaujíma, čo mu už poslala a čo mu poslať nestihla. Tento článok je o tom, ako sa k takej požiadavke postaviť triezvo: kedy dáva zmysel, aké možnosti existujú, čo každá z nich stojí a aké pasce čakajú v momente, keď spojenie spadne alebo dvaja ľudia upravia ten istý záznam.
Potrebujete naozaj real-time, alebo len čerstvejšie dáta?
Prvá otázka nie je technická, ale produktová: čo zlé sa stane, keď používateľ uvidí údaj starý pätnásť sekúnd? Pri veľkej časti firemných aplikácií je odpoveď „nič“. Vedúci pozerajúci na prehľad nepotrebuje, aby sa čísla menili priamo pred očami — potrebuje, aby neboli včerajšie. Dispečer prideľujúci vozidlá alebo dvaja ľudia v spoločnom formulári sú iný prípad; tam oneskorenie priamo spôsobuje kolízie a duplicitnú prácu.
Pomáha rozdeliť obrazovky do troch skupín:
- Skutočný real-time (do sekundy). Rozhodnutie sa robí okamžite a viacerí ľudia pracujú s tým istým objektom: chat, súbežná editácia, dispečing, monitoring s alarmami.
- Čerstvé dáta (jednotky až desiatky sekúnd). Zoznamy objednávok, stavy úloh, prevádzkové prehľady. Používateľ toleruje krátke oneskorenie, len nechce klikať na tlačidlo obnoviť.
- Dávkové zobrazenie. Reporty, uzávierky, prehľady za obdobie. Tu je „živosť“ skôr na škodu — čísla, ktoré sa menia počas čítania, sa zle interpretujú a ešte horšie porovnávajú.
Druhá skupina je v praxi najpočetnejšia a takmer vždy jej stačí periodické načítavanie. Klient sa každých pár sekúnd spýta servera, či je niečo nové; s podmienenými požiadavkami (ETag, If-Modified-Since) je odpoveď väčšinou prázdna a lacná. Keď je záložka na pozadí, interval sa predĺži alebo zastaví. Nevzniká žiadna nová infraštruktúra, prejde to cez každý firemný proxy server, chyby sa ladia bežnými nástrojmi a opakovanie požiadavky je zabudované v samotnom princípe. Ak je cieľom hlavne to, aby vedenie videlo aktuálne čísla bez ručného exportu, tému rozoberáme podrobnejšie v texte o reportoch pre vedenie firmy v reálnom čase.
Polling, SSE a WebSockety: čo každá voľba stojí
Ak ste si prešli predchádzajúcim filtrom a real-time naozaj potrebujete, výber prenosovej vrstvy je hlavne rozhodnutie o prevádzke, nie o rýchlosti. Všetky varianty vedia doručiť dáta dosť rýchlo; líšia sa tým, čo od vás potom chcú každý deň.
| Prístup | Tok dát | Typická latencia | Prevádzková náročnosť | Kedy je dobrá voľba |
|---|---|---|---|---|
| Periodický polling | klient sa pýta | interval (napr. 5–30 s) | najnižšia | prehľady, zoznamy, stavy úloh |
| Long polling | klient sa pýta, server drží | takmer okamžite | stredná | keď potrebujete rýchlosť, ale nie obojsmernosť |
| Server-sent events (SSE) | server → klient | takmer okamžite | stredná | notifikácie, živé grafy, streamované odpovede |
| WebSockety | obojsmerne | najnižšia | najvyššia | chat, súbežná editácia, hry, dispečing |
| Hostovaná real-time služba | podľa poskytovateľa | takmer okamžite | nízka vývojovo, vyššia finančne | malý tím, ktorý nechce prevádzkovať vlastnú vrstvu |
Server-sent events sú u nás v projektoch najčastejšie podceňovanou voľbou. Ide o obyčajné HTTP spojenie, ktoré server nechá otvorené a posiela doň riadky textu. Automatické obnovenie spojenia aj číslovanie správ sú súčasťou štandardu, funguje to cez bežnú HTTP infraštruktúru a na strane servera nepribúda samostatný protokol. Ak potrebujete len smer „zo servera k používateľovi“ — a pri notifikáciách a živých grafoch to je presne ten prípad — WebSockety sú často zbytočne ťažké riešenie.
WebSockety si vyberte vtedy, keď klient reálne posiela veľa správ späť a záleží na poradí a latencii oboch smerov. Cenou je vlastný protokol nad spojením, vlastná autentifikácia a autorizácia pre každú správu a nutnosť riešiť to, čo HTTP rieši za vás. Rozdiel medzi technológiami je v konečnom dôsledku menší než rozdiel medzi „máme to zapnuté“ a „vieme to prevádzkovať“, čo je téma, ktorej sa venujeme aj pri návrhu webových aplikácií na mieru.
Každé otvorené spojenie je malý kus stavu, ktorý musíte niekde držať, platiť zaň a raz aj korektne zavrieť.
Stav, ktorý sa rozpadne: prečo real-time UI potrebuje rekonciliáciu
Toto je bod, na ktorom padne väčšina prvých implementácií. Vývojár otestuje funkciu na wi-fi v kancelárii, vidí, že správy chodia, a považuje vec za hotovú. Realita je ale iná: mobilná sieť sa prepne, notebook si zdriemne, firemný proxy server zabije nečinné spojenie po minúte, nasadenie novej verzie odpojí naraz všetkých. Používateľ pritom nedostane žiadne varovanie — obrazovka jednoducho prestane žiť a tvári sa, že je aktuálna.
Preto platí jednoduché pravidlo: tok správ nie je zdroj pravdy, je to len optimalizácia. Zdrojom pravdy zostáva server a rozhranie musí mať cestu, ako sa s ním kedykoľvek zosúladiť. Prakticky to znamená tri veci:
- Detekcia. Pravidelný heartbeat oboma smermi a viditeľný indikátor stavu spojenia. Ak používateľ vidí „spojenie obnovujeme“, nespraví rozhodnutie nad mŕtvymi dátami.
- Obnova. Po opätovnom pripojení buď dotiahnite chýbajúce udalosti od posledného známeho poradového čísla, alebo — čo je jednoduchšie a pre väčšinu aplikácií úplne postačujúce — načítajte celý stav obrazovky nanovo a stream použite až od toho momentu.
- Idempotencia. Počítajte s tým, že správa príde dvakrát alebo v inom poradí. Spracovanie udalosti musí byť bezpečné opakovať, inak sa vám v zozname objavia duplicity, ktoré nikto nevie vysvetliť.
Optimistické zmeny a konflikty pri súbežnej editácii
Optimistické UI — teda zobrazenie zmeny okamžite, ešte pred potvrdením servera — je to, čo dáva aplikácii pocit svižnosti. Zároveň je to najčastejší zdroj tichých nekonzistencií. Každá optimistická zmena potrebuje tri stavy: čakajúca, potvrdená, zamietnutá. Zamietnutie musí vedieť zmenu vrátiť späť a zrozumiteľne to oznámiť, nie ju len ticho prepísať.
Pri súbežnej editácii sa rozhodujete medzi tromi režimami. Najjednoduchší je zámok na zázname — kým s ním niekto pracuje, ostatní vidia len na čítanie; je to nepohodlné, ale predvídateľné. Druhou možnosťou je verzovanie na úrovni záznamu: klient posiela verziu, ktorú videl, a server odmietne zápis nad novšou verziou. Tretia, najdrahšia možnosť je zlučovanie na úrovni polí alebo dátové štruktúry navrhnuté na automatické zlučovanie, ktoré potrebujete prakticky len pri spoločnom písaní textu.
Škálovanie real-time vrstvy
Dokým beží jeden aplikačný server, je všetko jednoduché: udalosť vznikne, server ju pošle svojim pripojeným klientom. V momente, keď pridáte druhý server, prestane to fungovať — používateľ pripojený na server A sa nedozvie o udalosti, ktorá vznikla na serveri B. Riešením je správcová vrstva, cez ktorú si servery udalosti navzájom rozposielajú: message broker alebo publish/subscribe kanál.
S tým súvisia ďalšie tri veci, ktoré treba vyriešiť skôr než v produkcii, nie potom:
- Prilepené relácie a časové limity. Load balancer musí vedieť, že spojenie má zostať na tom istom uzle, a jeho limit nečinnosti musí byť dlhší než interval heartbeatu.
- Limity počtu spojení. Jedno spojenie spotrebuje pamäť a systémový deskriptor. Kapacita uzla sa tak neplánuje podľa počtu požiadaviek za sekundu, ale podľa počtu súčasne prihlásených ľudí.
- Nával po nasadení. Reštart odpojí všetkých naraz a všetci sa naraz pokúsia pripojiť späť. Bez exponenciálneho odstupu s náhodným rozptylom si tým aplikácia zloží vlastný štart.
Nezabudnite ani na autorizáciu. Pri klasickom HTTP sa oprávnenia overujú pri každej požiadavke; pri dlho otvorenom spojení sa overia raz pri pripojení a potom môže človek prísť o prístup, no dáta mu chodia ďalej. Kontrola musí byť pri odosielaní každej správy. Širšiemu kontextu rastu záťaže sa venujeme v článku o škálovaní webovej aplikácie s rastom firmy.
Dizajn notifikácií: kanál, dávkovanie a pozornosť
Technická časť notifikácií je jednoduchšia než tá produktová. Rozhodnutie, ktoré rozhoduje o úspechu, znie: ktorá udalosť si zaslúži vyrušiť človeka a ktorá má len ticho počkať v aplikácii.
| Kanál | Vhodný pre | Hlavné riziko |
|---|---|---|
| In-app zoznam | bežné udalosti, kontext práce | používateľ ho nemusí otvoriť |
| Push do prehliadača | časovo citlivé udalosti | povolenie sa dá udeliť len raz, odmietnutie je trvalé |
| súhrny, veci na neskôr | ľahko skončí v zabudnutom priečinku | |
| SMS a volanie | kritické zlyhania, pohotovosť | drahé a rušivé; len pre úzku skupinu |
Pár zásad, ktoré sa osvedčili bez ohľadu na odvetvie: nikdy neupozorňujte človeka na jeho vlastnú akciu; zlučujte súvisiace udalosti do jednej správy s odstupom niekoľkých minút namiesto piatich samostatných; dajte nastavenia podľa typu udalosti, nie len jeden vypínač na všetko; a synchronizujte stav „prečítané“ medzi zariadeniami, inak používateľ rieši to isté dvakrát. Ak uvažujete o push notifikáciách bez natívnej aplikácie, prakticky ide o tému progresívnych webových aplikácií — a treba počítať s tým, že podpora sa medzi platformami stále líši.
Prevádzková daň: čo real-time pridá k monitoringu a testovaniu
Real-time funkcie prinášajú triedu chýb, ktorú klasické monitorovanie nezachytí. Server odpovedá, chybovosť je nula, stránka sa načíta rýchlo — a napriek tomu polovica používateľov vidí staré dáta, lebo im pred hodinou spadlo spojenie a nikdy sa neobnovilo. Preto potrebujete merať iné veci: počet aktívnych spojení, mieru opätovných pripojení, oneskorenie medzi vznikom udalosti a jej doručením, počet nedoručených správ a hĺbku frontu v brokeri.
Testovanie je podobná kapitola. Automatizované testy musia vedieť otvoriť dve relácie naraz a overiť, že akcia v jednej sa prejaví v druhej; musia vedieť spojenie umelo prerušiť a skontrolovať, že sa stav dorovnal. Záťažový test musí simulovať tisíc súčasne otvorených spojení, nie tisíc požiadaviek za sekundu — to sú úplne odlišné scenáre. Ako takéto scenáre zapadajú do celkového procesu kontroly kvality, popisujeme v texte o QA procese pred spustením softvéru.
Rátajte aj s tým, že real-time vrstva je zdrojom nákladov, ktoré nezmiznú po odovzdaní projektu. Otvorené spojenia sa platia časom, nie požiadavkami, takže mesačný účet rastie s počtom prihlásených ľudí aj vtedy, keď nikto nič nerobí.
Zhrnutie
Real-time webová aplikácia nie je funkcia, ktorú „dorobíte na konci“ — je to rozhodnutie o architektúre, prevádzke a rozpočte na ďalšie roky. Postup, ktorý sa osvedčil, je nudný, ale funguje: najprv pomenujte konkrétne rozhodnutie, ktoré oneskorenie pokazí; ak také nie je, spravte polling a hotovo. Ak je, vyberte najjednoduchšiu vrstvu, ktorá stačí — pri smerovaní zo servera k používateľovi sú to zvyčajne server-sent events. Potom, ešte pred prvým riadkom UI, navrhnite, ako sa stav dorovná po výpadku, a až nakoniec riešte optimistické zmeny a konflikty.
Notifikácie navrhujte ako produkt, nie ako technický vedľajší produkt: menej správ v správnom kanáli má vždy väčšiu hodnotu než všetko okamžite všade. A počítajte s tým, že monitoring a testovanie budú stáť viac než pri bežnej aplikácii — je to daň, ktorú platíte za to, že obrazovka žije.
Ak zvažujete, či má vo vašej aplikácii real-time zmysel a v akom rozsahu, radi to s vami prejdeme na konkrétnych obrazovkách — ozvite sa nám a začneme tým, čo sa naozaj musí diať okamžite.