Kao u
Jednog dana me probudio nezadovoljni e-mail zbog dugih kašnjenja s Alvinom, koji smo planirali uskoro pokrenuti. Konkretno, klijent je iskusio kašnjenje od 99. percentila u području od 50 ms, što je znatno iznad našeg budžeta za kašnjenje. Ovo je bilo iznenađujuće jer sam opsežno testirao uslugu, posebno na kašnjenju, što je uobičajena žalba.
Prije nego što sam stavio Alvina u testiranje, izveo sam mnogo eksperimenata sa 40 upita u sekundi (QPS), a svi su pokazali kašnjenje manju od 10 ms. Bio sam spreman da izjavim da se ne slažem sa njihovim rezultatima. Ali pogledavši još jednom pismo, primetio sam nešto novo: nisam baš testirao uslove koje su oni spomenuli, njihov QPS je bio mnogo niži od mog. Testirao sam na 40k QPS, ali oni samo na 1k. Izveo sam još jedan eksperiment, ovaj put sa nižim QPS-om, samo da ih umirim.
Pošto pišem na blogu o ovome, verovatno ste već shvatili da su njihovi brojevi tačni. Testirao sam svog virtuelnog klijenta iznova i iznova, sa istim rezultatom: mali broj zahteva ne samo da povećava kašnjenje, već povećava broj zahteva sa kašnjenjem većim od 10 ms. Drugim riječima, ako je pri 40k QPS oko 50 zahtjeva u sekundi premašilo 50 ms, onda je pri 1k QPS bilo 100 zahtjeva iznad 50 ms svake sekunde. Paradoks!
Sužavanje pretrage
Kada se suočite sa problemom kašnjenja u distribuiranom sistemu sa mnogo komponenti, prvi korak je kreiranje kratke liste osumnjičenih. Kopajmo malo dublje u Alvinovu arhitekturu:
Dobra polazna tačka je lista završenih I/O tranzicija (mrežni pozivi/pretraživanja diska, itd.). Pokušajmo otkriti gdje je kašnjenje. Pored očiglednog I/O sa klijentom, Alvin preduzima dodatni korak: pristupa skladištu podataka. Međutim, ovo skladište radi u istom klasteru kao i Alvin, tako da bi latencija tamo trebala biti manja nego kod klijenta. Dakle, lista osumnjičenih:
- Mrežni poziv od klijenta do Alvina.
- Mrežni poziv od Alvina prema spremištu podataka.
- Pretražite na disku u skladištu podataka.
- Mrežni poziv iz skladišta podataka za Alvina.
- Mrežni poziv od Alvina klijentu.
Pokušajmo precrtati neke tačke.
Skladištenje podataka nema nikakve veze s tim
Prva stvar koju sam uradio je konvertovanje Alvina u ping-ping server koji ne obrađuje zahteve. Kada primi zahtjev, vraća prazan odgovor. Ako se latencija smanji, onda greška u implementaciji Alvina ili skladišta podataka nije ništa nečuveno. U prvom eksperimentu dobijamo sledeći grafikon:
Kao što vidite, nema poboljšanja kada koristite ping-ping server. To znači da skladište podataka ne povećava latencije, a lista osumnjičenih je prepolovljena:
- Mrežni poziv od klijenta do Alvina.
- Mrežni poziv od Alvina klijentu.
Odlično! Lista se brzo smanjuje. Mislio sam da sam skoro shvatio razlog.
gRPC
Sada je vrijeme da vas upoznamo sa novim igračem: gRPC
dobro optimiziran i široko korišten, ovo je bio moj prvi put da ga koristim na sistemu ove veličine i očekivao sam da će moja implementacija biti suboptimalna - u najmanju ruku.
dostupnost gRPC
u stogu doveo do novog pitanja: možda je to moja implementacija ili ja gRPC
uzrokuje problem kašnjenja? Dodavanje novog osumnjičenog na listu:
- Klijent poziva biblioteku
gRPC
- biblioteka
gRPC
upućuje mrežni poziv biblioteci na klijentugRPC
na serveru - biblioteka
gRPC
kontakti Alvin (nema operacije u slučaju ping-pong servera)
Da vam dam ideju kako izgleda kod, moja implementacija klijent/Alvin se ne razlikuje mnogo od klijent-server implementacije
Napomena: Gornja lista je malo pojednostavljena jer
gRPC
omogućava korištenje vašeg vlastitog (template?) threading modela, u kojem je izvršni stek isprepletengRPC
i implementacija korisnika. Radi jednostavnosti, mi ćemo se zadržati na ovom modelu.
Profilisanje će sve popraviti
Pošto sam precrtao skladišta podataka, mislio sam da sam skoro gotov: „Sada je lako! Primijenimo profil i saznamo gdje dolazi do kašnjenja.” I
Uzeo sam četiri profila: sa visokim QPS-om (malo kašnjenje) i sa ping-pong serverom sa niskim QPS-om (visoka latencija), i na strani klijenta i na strani servera. I za svaki slučaj, uzeo sam i uzorak profila procesora. Kada upoređujem profile, obično tražim anomalan stek poziva. Na primjer, na lošoj strani s velikom latencijom postoji mnogo više promjena konteksta (10 puta ili više). Ali u mom slučaju, broj prebacivanja konteksta bio je skoro isti. Na moj užas, tu nije bilo ništa značajno.
Dodatno otklanjanje grešaka
Bio sam očajan. Nisam znao koje bih druge alate mogao koristiti, a moj sljedeći plan je u suštini bio da ponovim eksperimente s različitim varijacijama umjesto da jasno dijagnosticiram problem.
Šta ako
Od samog početka sam bio zabrinut zbog specifičnog kašnjenja od 50 ms. Ovo je veoma veliki trenutak. Odlučio sam da ću izrezati komade koda dok ne shvatim koji je dio tačno uzrokovao ovu grešku. Zatim je uslijedio eksperiment koji je uspio.
Kao i obično, gledajući unazad, čini se da je sve bilo očigledno. Postavio sam klijenta na istu mašinu kao i Alvin - i poslao zahtev localhost
. I povećanje latencije je nestalo!
Nešto nije u redu s mrežom.
Učenje vještina mrežnog inženjera
Moram priznati: moje poznavanje mrežnih tehnologija je užasno, pogotovo ako se uzme u obzir da svakodnevno radim s njima. Ali mreža je bila glavni osumnjičeni i morao sam naučiti kako da je otklonim.
Srećom, internet voli one koji žele da uče. Kombinacija pinga i tracerta se činila kao dovoljno dobar početak za otklanjanje grešaka u mrežnom transportu.
Prvo sam lansirao
Onda sam pokušao
Dakle, kašnjenje nije uzrokovao moj kod, gRPC implementacija ili mreža. Počeo sam da brinem da ovo nikada neću razumeti.
Sad na kom OS-u smo
gRPC
široko se koristi na Linuxu, ali egzotično na Windowsima. Odlučio sam isprobati eksperiment, koji je uspio: kreirao sam Linux virtuelnu mašinu, kompajlirao Alvin za Linux i postavio ga.
I evo šta se dogodilo: Linux ping-pong server nije imao ista kašnjenja kao sličan Windows host, iako izvor podataka nije bio ništa drugačiji. Ispostavilo se da je problem u gRPC implementaciji za Windows.
Nagleov algoritam
Sve ovo vrijeme sam mislio da mi nedostaje zastava gRPC
. Sada shvatam šta je to zaista gRPC
Windows zastavica nedostaje. Našao sam internu RPC biblioteku za koju sam bio siguran da će dobro raditi za sve postavljene zastavice
Skoro Gotovo: Počeo sam da uklanjam dodane zastavice jednu po jednu dok se regresija ne vrati kako bih mogao precizno odrediti uzrok. Bilo je neslavno
gRPC
ova zastavica je postavljena u Linux implementaciji za TCP utičnice, ali ne i u Windowsu. Ja sam ovo
zaključak
Veća latencija pri niskom QPS bila je uzrokovana optimizacijom OS-a. Retrospektivno, profiliranje nije otkrilo kašnjenje jer je urađeno u kernel modu, a ne u
Što se tiče eksperimenta sa lokalnim hostom, verovatno nije doticao stvarni mrežni kod i Nagleov algoritam se nije pokrenuo, tako da su problemi sa kašnjenjem nestali kada je klijent došao do Alvina preko lokalnog hosta.
Sljedeći put kada vidite povećanje latencije kako se broj zahtjeva u sekundi smanjuje, Nagleov algoritam bi trebao biti na vašoj listi osumnjičenih!
izvor: www.habr.com