Implementari WebSocket

Voi ce experienta aveti in cand vine vorba de WebSocket? In ce limbaje ati implementat server-ul? Care a fost numarul maxim de clientiti pe care trebuie sa-i suporte o instanta?

Recent am propus doua solutii pentru nevoia de live updates in aplicatie. Prima long-pooling, a doua websockets :smiley: , destul de la obiect.

Si tinand cont ca deja exista un micro-serviciu pentru asta, dezvoltat cu un an in urma si niciodata pus in practica, a trebuit sa rulez un benchmark si sa evaluez situatia.

Iar rezultatele nu au fost neaprat cele mai bune, cu cat crestea numarul de clientii conectat cu atat aplicatia consuma mult mai mult RAM (8GB max) iar la 3K tot timpul ceva nu mai functioneaza si totul se inchide.

Nevoia reala a feature-ului este pentru perioada de examene AP in US, adica exact cand ar exista si varful de clienti conectati, nu e un numar clar, dar ar fi de asteptat 20K constant.

Tinand cont ca stack-ul este python (fastapi + ws) nu pare ca ar mai merge ceva optimizat. Bineinteles poate analizand aplicatia mai in detaliu si implementand solutii in CPython, poate :roll_eyes:. Dar realistic vorbind, nimeni nu are timp de astea, plus ca e costisitor si dpdv al intretinerii si al banilor sa rulezi mai multe instance pentru ceva ce ar putea fi mult mai optim.

Propunerea mea e node.js folosind aceasta librarie incredibil de performanta: GitHub - uNetworking/uWebSockets.js: μWebSockets for Node.js back-ends 🤘. Dar tinand cont ca nu exista niciun alt serviciu baza pe node.js ar fi mai greu de luat in calcul.

Asa vin sa va intreb pe voi, ce experiente aveti cu websockets? A folosit cineva WebTransport pana acum? Pare foarte optimizat, promitator si HTTP/3 chiar este suportat in majoritatea browser-urilor. M-am simtit out-dated si vechi cand am dat de existenta WebTransport si QUIC :laughing:.

Am folosit mai multe tehnologii dar nu am avut nevoi de performanta ca cele descrise mai sus, pana în 1000 de sesiuni concurente la server. Cu ce am mai lucrat și sunt ok:

  • signalR ce mia placut e ca face automat downgrade la long-polling daca WS e blocat si are destul de multe features pe zona de enterprise (logging etc…), are si varianta hostata pe azure daca ai nevoi de performanta variabile.
  • SSE - pentru comunicare doar Server → Client pentru a primi update-uri în timp real
    How to use server-sent events (SSE) with FastAPI? aici am folosit sa trimit update-uri in format json la client
3 Likes

Am folosit SSE cu success

Eu fac, printre altele, si aplicatii de timp real cu websockets in Python pentru controlere IoT. Nu am un numar neaparat mare de conexiuni concurente dar am cereri catre server din frontend (Vue.js), in bucla, la intervale de ordinul milisecundelor. Oricum numarul de clienti se opreste acolo unde esti limitat de resurse.
Gestiunea intreruperilor de conexiune de departe mi-a pus mari probleme, pot detalia daca subiectul e de interes. In backend am folosit ca dependente externe doar websockets si aiohttp.

Acolo probabil este vorba de un bad design in urma caruia apare un memory leak necontrolat.

Websockets ca si protocol in sine nu este un consumator de resurse dar cererile transporta date, apoi sunt procesarile si raspunsurile care trebuie generate, mai folosesti si protocoale de data exchange (JSON,XML,etc), prin urmare, la un numar semnificativ de conexiuni vor fi necesita resurse.

Pe de alta parte poolingul, in diverse forme, este o solutie mult mai fiabila dar si mai lenta. Pentru transfer prin pooling eu de exemplu folosesc un cache facut in Go cu REST API peste el (vezi aici).

In astfel de aplicatii si platforme unde criteriile sunt performanta si disponibilitatea evit pe cat posibil sa folosesc librarii si proiecte terte intrucat m-am mai pacalit cu proiecte care au disparut de pe piata. Eu personal lucrez in circuit inchis in astfel de situatii dar nu sunt neaparat un exemplu in acest sens.

Aceasta este din punctul meu de vedere o greseala destul de frecventa. Din motivele mentionate de tine din dar si din altele oamenii evita scalarea pe orizontala in favoarea celei pe verticala ceea ce rezolva o problema pe termen scurt da creaza o multime pe termen lung. Stiu ca e mai complicat dar scalarea pe orizontala iti va rezolva, pe viitor, elegant si dileme de genul cel mai bun limbaj sau cea mai rapida tehnologie pentru ca nu va mai conta ce alegi cata vreme scalezi corespunzator. Desigur asta depinde si de importanta proiectului.

Multumesc pentru raspunsul detaliat!

Gestiunea intreruperilor de conexiune de departe mi-a pus mari probleme, pot detalia daca subiectul e de interes. In backend am folosit ca dependente externe doar websockets si aiohttp .

Da, imi este de interes si citind si mai mult despre subiect, imi dau seama ca aici intervin problemele cele mai subtile, daca le pot numi asa. Cum sunt gestionate conexiunile active in asa fel incat clientii cu conexiune slaba ori care blocheaza reteaua fiindca nu primesc mesajele (Backpresure cum e explicat aici) sa nu ii afecteze pe restul.
Dar in cazul meu nu este o tragedie daca conexiunea este inchisa, daca ceva merge pros in cel mai rau caz user-ul trebuie sa dea un refresh. Asa ca pentru dilema asta pot face implementa edge-case-urile mai usor.

Aceasta este din punctul meu de vedere o greseala destul de frecventa. Din motivele mentionate de tine din dar si din altele oamenii evita scalarea pe orizontala in favoarea celei pe verticala ceea ce rezolva o problema pe termen scurt da creaza o multime pe termen lung. Stiu ca e mai complicat dar scalarea pe orizontala iti va rezolva, pe viitor, elegant si dileme de genul cel mai bun limbaj sau cea mai rapida tehnologie pentru ca nu va mai conta ce alegi cata vreme scalezi corespunzator. Desigur asta depinde si de importanta proiectului.

Da, este si as fi vrut cu tot dinadinsul sa putem rezolva problema actuala, faptul ca pentru fiecare conexiune creste semnificativ nevoia de memorie. Dar tinand cont ca nu e o nevoie acuta in aplicatie, POs nu prea vor sa isi bata capul prea mult, adica prefera sa dezoltam alte feature-uri ori bug-fixing decat sa “irosim” trimpul pe web-sockets.

Si probabil nu se va intampla pe implementarea actuala, iar in opinia mea nici nu ar trebui, fiindca nu mi se pare ca au pornit cu ideea de optimizare din start pentru un bun balans conexiuni vs resurse consumate.

Eu mizez pe node.js fiindca acolo am mult mai multa experienta.

Websockets ca si protocol in sine nu este un consumator de resurse dar cererile transporta date, apoi sunt procesarile si raspunsurile care trebuie generate, mai folosesti si protocoale de data exchange (JSON,XML,etc), prin urmare, la un numar semnificativ de conexiuni vor fi necesita resurse.

Chiar nu este, citind ce scrie autorul librarieri de mai sus, chiar si un Raskberry PI poate sustine 700k conexiuni active.

Nici eu nu am fost pus in situatia de a scala volumul asta de clienti pana acum, dar e super interesant, aflu si mai multe despre linux, kernel, sockets si altele.

Da, varianta Microsoft nu e potrivita deloc, infrastructura actuala este pe AWS iar un stack de C# e clar iesit din discutie, nu stiu nici eu si probabil nici altii.

Dar signalR pare a fi o solutie completa, sunt chiar curios de cate servere e nevoie pentru 20k conexiuni active.

SSE ar functiona, dar nu a parut nimeni prea incantat de varianta asta, probabil fiindca in viitor vor fi si alte functionalitati adaugate cu nevoie de websocket, asa ca ar fi doar ceva provizoriu pana oricum va trebui implementat serviciu de genul.

Websockets everywhere…
Pot sa te întreb totuși de ce atâta nevoie de ws si atat de putin nevoie de stateless?

Depinde si de usecase. Firebase Realtime Db suporta 200k conexiuni simultane.

Eu folosesc realtime db pentru a aduce datele de la server la client in timp real si REST API cand clientul vrea sa modifice ceva. API-ul rest poate scala orizontal cat e nevoie, DB-ul e treaba Firebase.

Bine nu am avut mai mult de 1.9k useri activi non-stop dar la un cost foarte mic.

1 Like

GitHub - cirospaciari/socketify.py: Bringing Http/Https and WebSockets High Performance servers for PyPy3 and Python3

Seems fast enough.

Ai nevoie de websockets doar daca ai nevoie de comunicare bidirectionala, daca e doar server->client atunci poti utiliza si Server Sent Events sau edge serverless (faci request-uri pe endpoint-uri efemere mici).

SSE + REST pe edge cu endpoint-uri stateless e o solutie mai buna din punct de vedere al bateriei, dar mai proasta ca si cod/arhitectura.

Mai poti utiliza cum a recomandat si andrei o baza de date realtime sau distribuita pe client, inclusiv SQLite are ceva actualizari majore pe front-end, se poate utiliza in mod distribuit cu Origin Private File System. (ma uitam la ElectricSQL · Local-first. Electrified. (electric-sql.com) si ElectricSQL - Sync for modern apps (electric-sql.com), Proof of concept: expo-sqlite integration with CR-SQLite - Expo Changelog - dar e relativ simplu de facut si de la 0)

@kilogrammer

Websockets everywhere…
Pot sa te întreb totuși de ce atâta nevoie de ws si atat de putin nevoie de stateless?

Pai, in primul rand nu a existat o asa mare nevoie de websockets nici pana acum, aplicatia functioneaza bine-mersi si fara, SPA + micro-servicii. Noi venim cu solutii, sfaturi si implementari si stim doar cateva din planurile corporatiei mama, probabil in viitor au in plan alte chestii si pentru a pregatii terenul vor sa adauge websockets in aplicatie.

Mie unul mi se pare interesanta provocarea, dar si la mine prima reactie a fost: chiar e nevoie? Adica datele sunt la un refresh distanta.

@andrei-tatar

Depinde si de usecase. Firebase Realtime Db suporta 200k conexiuni simultane.

Eu folosesc realtime db pentru a aduce datele de la server la client in timp real si REST API cand clientul vrea sa modifice ceva. API-ul rest poate scala orizontal cat e nevoie, DB-ul e treaba Firebase.

Bine nu am avut mai mult de 1.9k useri activi non-stop dar la un cost foarte mic.

Nice, stiu ca prin Firebase totul poate fi real-time chiar prin fasa. doar ca pentru noi ar veni alta dependenta, Google Cloud, si nu e nevoie cat tot restul lucrurilor sunt in AWS. Iar in AWS nu am vazut ceva similar, ori chiar simplu si frumos de implementat.

@isti37

GitHub - cirospaciari/socketify.py: Bringing Http/Https and WebSockets High Performance servers for PyPy3 and Python3

Seems fast enough.

Foarte misto, chiar nu am dat de el, si e exact ce e nevoie. Merci!!

Iar ceea ce mi se pare si mai interesant este ca la baza are tot libraria uWebSockets :smiley: .

1 Like

https://unetworkingab.medium.com/millions-of-active-websockets-with-node-js-7dc575746a01

2 Likes

Ai mentionat ceva legat de examenele AP, ce date au nevoie sa fie realtime prin ws?

Ai incercat Redis?
Suportă 10,000 de conexiuni per GB de memorie.

Poate fi extins la câteva sute de mii, bineînțeles la pretul memoriei.

Poti sa folosesti in aceeasi aplicatie un pinger separat.