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.