Ndonjëherë më shumë është më pak. Kur zvogëloni ngarkesën rezulton në rritjen e vonesës

Si në shumica e postimeve, ka një problem me një shërbim të shpërndarë, le ta quajmë këtë shërbim Alvin. Këtë herë nuk e zbulova vetë problemin, më njoftuan djemtë nga ana e klientit.

Një ditë u zgjova me një email të pakënaqur për shkak të vonesave të gjata me Alvinin, të cilin kishim planifikuar ta lansnim në të ardhmen e afërt. Në mënyrë të veçantë, klienti përjetoi vonesë të përqindjes së 99-të në rajonin prej 50 ms, shumë më tepër se buxheti ynë i vonesës. Kjo ishte befasuese pasi e testova gjerësisht shërbimin, veçanërisht në latente, që është një ankesë e zakonshme.

Përpara se të testoja Alvinin, bëra shumë eksperimente me 40 mijë pyetje në sekondë (QPS), të gjitha duke treguar vonesë prej më pak se 10 ms. Isha gati të deklaroja se nuk pajtohesha me rezultatet e tyre. Por duke i hedhur një sy letrës, vura re diçka të re: nuk i kisha testuar saktësisht kushtet që ata përmendën, QPS-ja e tyre ishte shumë më e ulët se e imja. Kam testuar në 40k QPS, por ato vetëm në 1k. Unë bëra një tjetër eksperiment, këtë herë me një QPS më të ulët, vetëm për t'i qetësuar ata.

Meqenëse po bëj blog për këtë, ju ndoshta e keni kuptuar tashmë se numrat e tyre ishin të saktë. Unë e testova klientin tim virtual vazhdimisht me të njëjtin rezultat: një numër i vogël kërkesash jo vetëm që rrit vonesën, por rrit numrin e kërkesave me vonesë më të madhe se 10ms. Me fjalë të tjera, nëse në 40k QPS kishte rreth 50 kërkesa në sekondë mbi 50ms, atëherë në 1k QPS kishte 100 kërkesa mbi 50ms çdo sekondë. Paradoks!

Ndonjëherë më shumë është më pak. Kur zvogëloni ngarkesën rezulton në rritjen e vonesës

Duke ngushtuar kërkimin

Kur përballemi me një problem vonesë në një sistem të shpërndarë me shumë komponentë, hapi i parë është krijimi i një liste të shkurtër të dyshuarish. Le të gërmojmë pak më thellë në arkitekturën e Alvinit:

Ndonjëherë më shumë është më pak. Kur zvogëloni ngarkesën rezulton në rritjen e vonesës

Një pikënisje e mirë është një listë e tranzicioneve I/O të kryera (thirrjet e rrjetit/kërkimet e diskut, etj.). Le të përpiqemi të kuptojmë se ku është vonesa. Përveç hyrjes/daljes së dukshme me klientin, Alvin ndërmerr një hap shtesë: ai hyn në dyqanin e të dhënave. Megjithatë, kjo hapësirë ​​ruajtëse funksionon në të njëjtin grup si Alvin, kështu që vonesa atje duhet të jetë më e vogël se sa tek klienti. Pra, lista e të dyshuarve:

  1. Thirrje në rrjet nga klienti drejt Alvinit.
  2. Thirrje në rrjet nga Alvin në dyqanin e të dhënave.
  3. Kërkoni në disk në dyqanin e të dhënave.
  4. Thirrje në rrjet nga depoja e të dhënave drejt Alvinit.
  5. Thirrje në rrjet nga Alvin drejt një klienti.

Le të përpiqemi të kalojmë disa pika.

Ruajtja e të dhënave nuk ka asnjë lidhje me të

Gjëja e parë që bëra ishte konvertimi i Alvin në një server ping-ping që nuk përpunon kërkesat. Kur merr një kërkesë, ai kthen një përgjigje boshe. Nëse vonesa zvogëlohet, atëherë një defekt në zbatimin e Alvin ose të magazinës së të dhënave nuk është asgjë e padëgjuar. Në eksperimentin e parë marrim grafikun e mëposhtëm:

Ndonjëherë më shumë është më pak. Kur zvogëloni ngarkesën rezulton në rritjen e vonesës

Siç mund ta shihni, nuk ka përmirësim kur përdorni serverin ping-ping. Kjo do të thotë që depoja e të dhënave nuk rrit vonesën, dhe lista e të dyshuarve është përgjysmuar:

  1. Thirrje në rrjet nga klienti drejt Alvinit.
  2. Thirrje në rrjet nga Alvin drejt një klienti.

E shkëlqyeshme! Lista po zvogëlohet shpejt. Mendova se pothuajse e kisha kuptuar arsyen.

gRPC

Tani është koha për t'ju prezantuar me një lojtar të ri: gRPC. Kjo është një bibliotekë me burim të hapur nga Google për komunikim në proces RPC... Megjithëse gRPC i optimizuar mirë dhe i përdorur gjerësisht, kjo ishte hera ime e parë që e përdorja atë në një sistem të kësaj madhësie dhe prisja që zbatimi im të ishte nën-optimal - për të thënë të paktën.

Disponueshmëria gRPC në pirg lindi një pyetje të re: ndoshta është zbatimi im ose unë gRPC duke shkaktuar problem latente? Shtimi i një të dyshuari të ri në listë:

  1. Klienti thërret bibliotekën gRPC
  2. Bibliotekë gRPC bën një thirrje rrjeti në bibliotekën e klientit gRPC në server
  3. Bibliotekë gRPC kontaktet me Alvin (nuk funksionon në rast të serverit të ping-pongut)

Për t'ju dhënë një ide se si duket kodi, zbatimi i klientit tim/Alvin nuk është shumë i ndryshëm nga ai klient-server shembuj asinkron.

Shënim: Lista e mësipërme është paksa e thjeshtuar sepse gRPC bën të mundur përdorimin e modelit tuaj të filetimit (shabllon?), në të cilin është ndërthurur pirgu i ekzekutimit gRPC dhe zbatimin e përdoruesit. Për hir të thjeshtësisë, ne do t'i përmbahemi këtij modeli.

Profilizimi do të rregullojë gjithçka

Pasi kalova dyqanet e të dhënave, mendova se kisha mbaruar pothuajse: "Tani është e lehtë! Le të aplikojmë profilin dhe të zbulojmë se ku ndodh vonesa." I adhurues i madh i profilizimit preciz, sepse CPU-të janë shumë të shpejta dhe më shpesh nuk janë pengesa. Shumica e vonesave ndodhin kur procesori duhet të ndalojë përpunimin për të bërë diçka tjetër. Profilizimi i saktë i CPU-së bën pikërisht këtë: regjistron me saktësi gjithçka ndërruesit e kontekstit dhe bën të qartë se ku ndodhin vonesat.

Kam marrë katër profile: me QPS të lartë (latente të ulët) dhe me një server ping-pong me QPS të ulët (latente të lartë), si në anën e klientit ashtu edhe në anën e serverit. Dhe për çdo rast, mora gjithashtu një profil shembullor të procesorit. Kur krahasoj profilet, unë zakonisht kërkoj një pirg thirrjesh anormale. Për shembull, në anën e keqe me vonesë të lartë ka shumë më tepër ndërprerës të kontekstit (10 herë ose më shumë). Por në rastin tim, numri i ndërruesve të kontekstit ishte pothuajse i njëjtë. Për tmerrin tim, nuk kishte asgjë të rëndësishme atje.

Korrigjim shtesë

Isha i dëshpëruar. Nuk e dija se çfarë mjetesh të tjera mund të përdorja dhe plani im i ardhshëm ishte në thelb të përsërisja eksperimentet me variacione të ndryshme në vend që të diagnostikoja qartë problemin.

Po nese

Unë isha i shqetësuar për vonesën specifike prej 50 ms që në fillim. Kjo është një kohë shumë e madhe. Vendosa që do të shkurtoja copa nga kodi derisa të kuptoja saktësisht se cila pjesë po shkaktonte këtë gabim. Pastaj erdhi një eksperiment që funksionoi.

Si zakonisht, në pamje të pasme duket se gjithçka ishte e qartë. E vendosa klientin në të njëjtën makinë si Alvin - dhe i dërgova një kërkesë localhost. Dhe rritja e vonesës është zhdukur!

Ndonjëherë më shumë është më pak. Kur zvogëloni ngarkesën rezulton në rritjen e vonesës

Diçka nuk shkonte me rrjetin.

Mësimi i aftësive të inxhinierit të rrjetit

Duhet të pranoj: njohuritë e mia për teknologjitë e rrjetit janë të tmerrshme, veçanërisht duke pasur parasysh faktin që punoj me to çdo ditë. Por rrjeti ishte i dyshuari kryesor dhe më duhej të mësoja se si ta korrigjoja atë.

Për fat të mirë, interneti i do ata që duan të mësojnë. Kombinimi i ping dhe tracert dukej si një fillim mjaft i mirë për korrigjimin e problemeve të transportit të rrjetit.

Së pari, nisa PsPing në portin TCP të Alvinit. Kam përdorur cilësimet e paracaktuara - asgjë e veçantë. Nga mbi një mijë ping, asnjë nuk i kaloi 10 ms, përveç të parës që u ngroh. Kjo është në kundërshtim me rritjen e vërejtur të vonesës prej 50 ms në përqindjen e 99-të: atje, për çdo 100 kërkesa, duhet të kishim parë rreth një kërkesë me një vonesë prej 50 ms.

Pastaj u përpoqa tracert: Mund të ketë një problem në një nga nyjet përgjatë rrugës midis Alvin dhe klientit. Por edhe gjurmuesi u kthye duarbosh.

Pra, nuk ishte kodi im, zbatimi i gRPC ose rrjeti që po shkaktonte vonesën. Kisha filluar të shqetësohesha se nuk do ta kuptoja kurrë këtë.

Tani me çfarë OS jemi

gRPC përdoret gjerësisht në Linux, por ekzotike në Windows. Vendosa të provoja një eksperiment, i cili funksionoi: Krijova një makinë virtuale Linux, përpilova Alvin për Linux dhe e vendosa atë.

Ndonjëherë më shumë është më pak. Kur zvogëloni ngarkesën rezulton në rritjen e vonesës

Dhe ja çfarë ndodhi: serveri ping-pong Linux nuk kishte të njëjtat vonesa si një host i ngjashëm i Windows, megjithëse burimi i të dhënave nuk ishte i ndryshëm. Rezulton se problemi është në zbatimin e gRPC për Windows.

Algoritmi i Nagle

Gjatë gjithë kësaj kohe mendova se më mungonte një flamur gRPC. Tani e kuptoj se çfarë është në të vërtetë gRPC Flamuri i Windows mungon. Gjeta një bibliotekë të brendshme RPC që isha i sigurt se do të funksiononte mirë për të gjithë flamujt e vendosur Winsock. Pastaj i shtova të gjithë këta flamuj në gRPC dhe vendosa Alvin në Windows, në një server ping-pong të Windows-it të rregulluar!

Ndonjëherë më shumë është më pak. Kur zvogëloni ngarkesën rezulton në rritjen e vonesës

pothuajse U krye: Fillova t'i heq flamujt e shtuar një nga një derisa të kthehej regresioni, në mënyrë që të mund të identifikoja shkakun. Ishte famëkeq TCP_NODELAY, ndërruesi i algoritmit të Nagle.

Algoritmi i Nagle përpiqet të zvogëlojë numrin e paketave të dërguara përmes një rrjeti duke vonuar transmetimin e mesazheve derisa madhësia e paketës të kalojë një numër të caktuar bajtash. Ndërsa kjo mund të jetë e këndshme për përdoruesin mesatar, është shkatërruese për serverët në kohë reale pasi OS do të vonojë disa mesazhe, duke shkaktuar vonesa në QPS të ulët. U gRPC ky flamur u vendos në zbatimin e Linux për bazat TCP, por jo në Windows. Unë jam ky korrigjohet.

Përfundim

Vonesa më e lartë në QPS të ulët u shkaktua nga optimizimi i OS. Në retrospektivë, profilizimi nuk zbuloi vonesë sepse ishte bërë në modalitetin kernel dhe jo në modaliteti i përdoruesit. Nuk e di nëse algoritmi i Nagle mund të vëzhgohet përmes kapjeve ETW, por do të ishte interesante.

Sa i përket eksperimentit të localhost, ai ndoshta nuk preku kodin aktual të rrjetit dhe algoritmi i Nagle nuk funksionoi, kështu që problemet e vonesës u larguan kur klienti arriti në Alvin përmes localhost.

Herën tjetër që do të shihni një rritje të vonesës pasi numri i kërkesave për sekondë zvogëlohet, algoritmi i Nagle duhet të jetë në listën tuaj të të dyshuarve!

Burimi: www.habr.com

Shto një koment