IZVRŠNI SAŽETAK

PROBLEM

Platforma za javna upozorenja koja je držala više od 350.000 trajnih WebSocket konekcija i primala oko 65.000 poruka u sekundi postala je nestabilna tokom simulacija hitnih situacija sa visokom konkurentnošću. Obrada JSON-a zasnovana na stablu podigla je alokaciju na oko 14,2 GB/s, što je dovelo do G1GC pauza dužih od 1,8 sekundi (najgori slučaj oko 4,2 sekunde), znatno preko heartbeat prozora od 1 sekunde. Konekcije su istekle masovno, a naknadni talasi ponovnog povezivanja generisali su dodatnu alokaciju: alokacija -> GC pauze -> heartbeat timeout-i -> masovni diskonekti -> reconnect oluja -> nova alokacija

REŠENJE

SWARCS je uklonio alokaciju na izvoru: parsiranje JSON-a u stablo zamenjeno je streaming parsiranjem, a suvišno kopiranje podataka i kreiranje objekata na kritičnoj putanji prijema je smanjeno. G1GC je zatim podešen prema smanjenom profilu alokacije kako bi se održao prostor za rezervu tokom naglih skokova opterećenja. Nije dodat nikakav računski kapacitet.

KLJUČNI ARHITEKTONSKI POMAK

OD ekstremno kreiranje kratkotrajnih objekata + nepredvidive višesekundne pauze
→
KA značajno niži pritisak na alokacije + predvidiv GC sa niskom latencijom

ZAKLJUČAK

U ciljnom simulacionom opterećenju: Stopa alokacije memorije: 14,2 GB/s -> 3,8 GB/s, p99 trajanje GC pauze: 1.800+ ms -> < 85 ms, Prekidi WebSocket konekcija: 18,5% -> 0,0%, Reconnect oluje: Ponavljajuće -> Nije primećeno, Iskorišćenost CPU-a: Zasićena osnova -> ~35% niža. Ključna promena bila je uklanjanje nepotrebne alokacije sa kritične putanje izvršavanja, a zatim podešavanje kolektora prema dobijenom opterećenju.

ARHITEKTONSKA ANALIZA

KONTEKST I POSLOVNI UTICAJ

Platforma prosleđuje hitna upozorenja, naloge za evakuaciju i telemetriju opasnosti u realnom vremenu po geografskim zonama ka mobilnim uređajima, terenskim terminalima i dispečerskim sistemima prvih responder-a.

  • zakasnela hitna obaveštenja
  • zaustavljenu mrežnu obradu tokom dugih JVM pauza
  • masovne prekide WebSocket konekcija nakon isteka heartbeat-a
  • talase ponovnog povezivanja koji povećavaju pritisak na infrastrukturu na ivici
  • kaskadnu degradaciju tokom vršnih simulacija hitnih situacija

Ključna karakteristika bila je povratna petlja. Pauza duža od heartbeat granice mogla je da pogodi mnoge konekcije istovremeno. Njihovi naknadni pokušaji ponovnog povezivanja dodavali su posao sistemu koji je već bio pod pritiskom runtime-a.

POVRATNA PETLJA OTKAZA

Prekomerna alokacija
          |
          v
     GC pritisak
          |
          v
   Duge STW pauze
          |
          v
  Istek heartbeat-a
          |
          v
 Masovni diskonekti
          |
          v
   Reconnect oluja
          |
          v
  Dodatna alokacija
          |
          +----------> GC pritisak

Inženjerski cilj je zato bio da se vrati predvidivo ponašanje runtime-a pri postojećoj skali rada, umesto oslanjanja na dodatni ukupni kapacitet koji bi apsorbovao istu neefikasnu putanju obrade.

UZROK I FORENZIKA

Sloj za prijem koristio je Spring Boot, reaktivni WebFlux i Netty na Java 17 LTS, sa oko 32 GB JVM heap-a po čvoru u klasteru od 8 čvorova. Tokom vršnih simulacija klaster je doživljavao WebSocket timeout-e, prekide konekcija i zasićenje CPU-a.

Povećanje infrastrukturnog kapaciteta nije uklonilo osnovni način otkaza: putanja prijema je i dalje generisala prekomeran privremeni posao za svaku dolaznu poruku.

Payload-i su u proseku imali ~30 KB i sadržali su geoprostorne podatke i telemetriju. Pri oko 65.000 poruka u sekundi, izmerena stopa alokacije odgovara otprilike 218 KB ukupne alokacije po primljenoj poruci:

ALOKACIJA PO PRIMLJENOJ PORUCI

14,2 GB/s / 65.000 poruka/s ~= 218 KB/poruci

Ovo je ukupna uočena alokacija podeljena brzinom prijema, a ne izolovano merenje alokacije JSON parsera; uključuje alokaciju iz šire putanje obrade. Merenje je utvrdilo razmere prolazne alokacije, a profilisanje je identifikovalo putanju parsiranja zasnovanu na stablu kao dominantan doprinos.

Dokazi su ukazivali na samopojačavajući mehanizam otkaza: prekomerna prolazna alokacija povećala je GC pritisak; ozbiljne pauze prekoračile su heartbeat granicu konekcije; masovni diskonekti generisali su dodatni posao.

Intervencija je zato morala da obuhvati i dominantni izvor alokacije i ponašanje kolektora pod dobijenim opterećenjem. Samo rešavanje simptoma reconnect-a ostavilo bi početni pritisak netaknutim.

ARHITEKTONSKI UVID I EVOLUCIJA

Horizontalno skaliranje bi povećalo ukupni kapacitet, ali ne bi uklonilo nepotrebno kreiranje objekata koje se obavlja za svaku poruku. Redizajn je zato obuhvatio dve odvojene stvari:

  • smanjiti izbegnutu alokaciju na kritičnoj putanji prijema
  • podesiti G1GC prema dobijenom opterećenju i zahtevima za latenciju

Smanjenje alokacije rešilo je izvor pritiska. Podešavanje GC-a rešilo je ponašanje runtime-a nakon što je taj pritisak smanjen.

OD MATERIJALIZACIJE STABLA DO SELEKTIVNOG PARSIRANJA

STARI TOK PRIJEMA

Mrežni payload
       |
       v
ObjectMapper stablo
deserijalizacija
       |
       v
Ceo graf objekata
+ privremeni objekti
       |
       v
Visoka stopa alokacije
    14,2 GB/s
       |
       v
GC pritisak i pauze
       |
       v
Heartbeat otkazi


REDIZAJNIRANI TOK PRIJEMA

Mrežni payload
       |
       v
Pooled Netty bafer
       |
       v
Jackson streaming parser
       |
       v
Selektivno izdvajanje polja
       |
       v
Niža stopa alokacije
    3,8 GB/s
       |
       v
G1GC podešen za opterećenje
       |
       v
Stabilne konekcije

KLJUČNE INŽENJERSKE ODLUKE

G1GC KONFIGURACIJA (JAVA 17)

-XX:+UseG1GC
-XX:MaxGCPauseMillis=200                 (podrazumevano u Javi 17)
-XX:InitiatingHeapOccupancyPercent=45    (podrazumevano u Javi 17)
-XX:G1ReservePercent=15
-XX:ConcGCThreads=8
-XX:G1HeapRegionSize=32m

U ovom opterećenju, konfiguracija je imala za cilj da:

  • održi dodatnu rezervu kapaciteta tokom naleta alokacije
  • obezbedi dovoljan kapacitet konkurentnog sakupljanja za ciljno opterećenje
  • smanji rizik od neuspeha evakuacije i ozbiljne eskalacije GC-a
  • očuva responzivnost aplikacije pod izmerenim opterećenjem

KVANTIFIKOVANI REZULTATI

Stopa alokacije memorije

PRE 14,2 GB/s
POSLE 3,8 GB/s

73% manje

p99 trajanje GC pauze

PRE 1.800+ ms
POSLE < 85 ms

95%+ manje

End-to-end latencija isporuke (p99)

PRE ~2,1 s
POSLE ~310 ms

U okviru ugovornog cilja od 500 ms

Full GC događaji

PRE 9 po testu
POSLE 0 po testu

Nakon promene nisu primećeni Full GC događaji

Prekidi WebSocket konekcija

PRE 18,5% pod vršnim opterećenjem
POSLE 0,0%

Nisu primećeni prekidi konekcija

Reconnect oluje

PRE Ponavljajuće
POSLE 0 događaja

Nije primećen nijedan događaj

Iskorišćenost CPU-a

PRE Zasićena osnova
POSLE ~35% niža

Povraćen kapacitet

Brojke se odnose na ceo klaster i izmerene su tokom tri testa od po 45 minuta ciljnog simulacionog opterećenja hitnih situacija.

Stopa alokacije pala je sa oko 14,2 GB/s na 3,8 GB/s, što je smanjenje od otprilike 73%. Pri brzini prijema od 65.000 poruka u sekundi, te stope odgovaraju otprilike 218 KB, odnosno 58 KB ukupne alokacije po primljenoj poruci. Ovo su izvedeni proseci na nivou klastera koji kvantifikuju opterećenje alokacije povezano sa obradom svake poruke, a ne izolovanu cenu alokacije parsera.

p99 trajanje GC pauze palo je sa više od 1,8 sekundi na ispod 85 ms, a najgora pauza uočena nakon promene iznosila je 112 ms. Prekidi konekcija pali su sa 18,5% na nula uočenih prekida, a tokom izmerenih testova nakon promene nisu primećene reconnect oluje.

Iskorišćenost CPU-a bila je oko 35% niža nakon intervencije. To je u skladu sa manje alokacije i posla garbage collection-a, uz smanjen prekid konekcija i povezanu obradu handshake-a. Klaster je povratio procesorski kapacitet bez povećanja računskog otiska.

Rezultati su dobijeni tokom simulacija hitnih situacija na produkcionoj platformi, a ne tokom stvarnog vanrednog događaja. Oni opisuju testirano opterećenje i period posmatranja i ne garantuju identične ishode pri drugačijim obrascima saobraćaja, hardveru, veličini heap-a ili runtime uslovima. Otkazi na nivou infrastrukture, kao što je gubitak mrežnog segmenta, bili su van izmerene promene, a otpornost klijentskog ponovnog povezivanja, uključujući exponential backoff sa jitter-om, je komplementaran sloj koji nije bio njen deo.

Merenja pokazuju da je platforma stabilizovana pod ciljnim opterećenjem bez dodavanja računskog kapaciteta. Kombinovana intervencija je smanjila pritisak alokacije i poboljšala uočeno ponašanje runtime-a; tokom izmerenih testova, raniji mehanizam otkaza usled dugih pauza više nije proizvodio reconnect oluje.

INŽENJERSKI DOPRINOS

SWARCS je izvršio runtime forenziku, profilisanje alokacija, optimizaciju putanje prijema i podešavanje JVM-a prilagođeno opterećenju, potrebno da se platforma stabilizuje.

ODGOVORNOSTI

  • profilisanje ponašanja alokacije na putanji prijema visoke propusnosti pomoću JFR-a
  • identifikacija izgradnje JSON stabla kao dominantnog izvora alokacije
  • zamena obrade JSON-a u stablo streaming JsonParser obradom
  • smanjenje nepotrebne alokacije i kopiranja mrežnih bafera
  • uklanjanje izbegnutog boxing-a primitiva u reprezentacijama na kritičnoj putanji
  • kontrolisano ponovno korišćenje objekata tamo gde ga je profilisanje opravdalo
  • procena i konfigurisanje G1GC-a za dobijeno opterećenje
  • validacija ponašanja kolektora u odnosu na heartbeat zahteve aplikacije
  • reprodukcija uslova visoke konkurentnosti sa više od 350.000 aktivnih WebSocket konekcija
  • validacija prijema pri oko 65.000 poruka u sekundi

KLJUČNA PORUKA

NE SKALIRAJ HORIZONTALNO DA BI SAKRIO PRITISAK ALOKACIJE.

PROFILIŠI KRITIČNU PUTANJU.
UKLONI NEPOTREBNU ALOKACIJU.
PODESI KOLEKTOR PREMA IZMERENOM OPTEREĆENJU.
POŠTUJ MREŽNE I APLIKACIONE ROKOVE.
PROVERI PONAŠANJE RUNTIME-A POD REALISTIČNIM OPTEREĆENJEM.
MERI NAČIN OTKAZA, A NE SAMO ISKORIŠĆENOST CPU-A.

U visokokonkurentnim JVM sistemima, dodatni hardver ne rešava nužno mehanizam zbog kojeg sistem postaje nestabilan. Kada prolazna alokacija izaziva višesekundne pauze garbage collection-a, lokalni runtime problem može da pređe granicu sistema: propušteni heartbeat-ovi prekidaju klijente, a talasi ponovnog povezivanja stvaraju dodatni posao u celoj platformi. Inženjerski zadatak je da se identifikuje i ukloni izvor tog pritiska, a zatim da se ponašanje kolektora i aplikacije proveri u odnosu na stvarne zahteve opterećenja za latenciju. U ovom slučaju, smanjenje nepotrebne alokacije promenilo je runtime uslove koji su garbage collection pretvorili u pojačavač distribuiranog otkaza.