Scalabilitate & performanță

Cum ține Recash pasul cu traficul, fără să încetinească și fără să cedeze sub abuz.

Recash a fost construit să rămână rapid și stabil pe măsură ce numărul de utilizatori crește. Deciziile principale luate în acest scop:

  • limitarea numărului de cereri, per utilizator sau per IP, prin Redis
  • cache pentru interogările care se repetă
  • indexuri stabilite pe interogările aplicației
  • contoare precalculate, actualizate incremental
  • servicii separate, scalabile independent

Limitarea traficului

Recash limitează câte cereri poate face cineva într-un interval de timp, iar identificarea depinde de tipul rutei: pe rutele care cer autentificare, limita se aplică per cont de utilizator; pe rutele publice — feed-ul de postări, clasamentul, geocodarea — limita se aplică per adresă IP, pentru că acolo nu există un cont de care cererile să fie legate.

Fiecare cerere este înregistrată în Redis cu momentul exact la care a sosit, iar la fiecare cerere nouă sistemul numără doar cererile din intervalul curent — cele mai vechi ies automat din calcul. Limita se raportează astfel mereu la intervalul imediat precedent și nu poate fi ocolită prin rafale trimise la granița dintre două intervale.

Limitele și intervalele diferă în funcție de cât de costisitoare este fiecare rută: citirile obișnuite au limite permisive, scrierile — postare, revendicare, finalizare — sunt mai stricte, chat-ul are propriile praguri, iar analiza AI este cea mai restricționată, cu un plafon orar per utilizator și unul global pe minut, pentru că fiecare apel către model costă.

Cache

Cache-ul este folosit pe scară largă în Recash — aproape tot ce se afișează pe un profil trece prin el: datele profilului, listele de postări, istoricul de tranzacții, badge-urile și chiar notificările, fiecare cu propria cheie per utilizator și per pagină. O funcție simplă verifică întâi Redis, iar dacă nu găsește nimic, calculează valoarea și o salvează cu un termen de expirare potrivit fiecărui tip de date — notificările, de exemplu, au un termen foarte scurt, pentru că se schimbă des.

La orice scriere care ar modifica acele date — o postare nouă, o tranzacție finalizată, un badge primit — cache-ul corespunzător se invalidează explicit, ca informația afișată să rămână mereu corectă.

Indexuri

Fiecare index din baza de date corespunde unei interogări care există în aplicație — nimic adăugat din prudență. Detalii complete în Arhitectura datelor.

Contoare precalculate

Numărul de sticle date, tranzacțiile totale, scorul de reputație — toate se actualizează incremental, la fiecare eveniment relevant, nu se adună din zero la fiecare afișare. Un profil se citește de mult mai multe ori decât se modifică, așa că efortul suplimentar la scriere se recuperează de fiecare dată la citire.

Scalare orizontală

Aplicația web și serverul WebSocket sunt două servicii separate, fiecare cu propria imagine Docker minimală. Pot fi scalate independent: mai multe replici Next.js în spatele unui load balancer, iar serverul WebSocket își partajează starea prin Redis, nu prin memorie locală — oricâte replici ar rula simultan, toate văd aceleași evenimente.