Soms is meer minder. Wanneer las verminder word, lei dit tot toenemende latensie

Soos in meeste plasings, daar is 'n probleem met 'n verspreide diens, kom ons noem hierdie diens Alvin. Hierdie keer het ek nie self die probleem ontdek nie, het die ouens van die kliënt se kant my ingelig.

Ek het eendag wakker geword van 'n ontevrede e-pos weens lang vertragings met Alvin, wat ons beplan het om in die nabye toekoms bekend te stel. Die kliënt het spesifiek 99ste persentiel latency in die omgewing van 50 ms ervaar, ver bo ons latensiebegroting. Dit was verbasend aangesien ek die diens breedvoerig getoets het, veral oor latensie, wat 'n algemene klagte is.

Voordat ek Alvin in die toets geplaas het, het ek baie eksperimente uitgevoer met 40k navrae per sekonde (QPS), wat almal latency van minder as 10ms toon. Ek was gereed om te verklaar dat ek nie met hul resultate saamstem nie. Maar terwyl ek weer na die brief kyk, het ek iets nuuts opgemerk: ek het nie presies die toestande wat hulle genoem het, getoets nie, hul QPS was baie laer as myne. Ek het getoets teen 40k QPS, maar hulle het net by 1k. Ek het nog 'n eksperiment uitgevoer, hierdie keer met 'n laer QPS, net om hulle te paai.

Aangesien ek hieroor blog, het jy seker al agtergekom dat hulle nommers reg was. Ek het my virtuele kliënt oor en oor getoets, met dieselfde resultaat: 'n lae aantal versoeke verhoog nie net die latensie nie, maar verhoog die aantal versoeke met 'n latensie van meer as 10 ms. Met ander woorde, as by 40k QPS ongeveer 50 versoeke per sekonde 50 ms oorskry het, dan was daar by 1k QPS 100 versoeke bo 50 ms elke sekonde. Paradoks!

Soms is meer minder. Wanneer las verminder word, lei dit tot toenemende latensie

Vernou die soektog

Wanneer 'n vertragingsprobleem in 'n verspreide stelsel met baie komponente gekonfronteer word, is die eerste stap om 'n kort lys van verdagtes te skep. Kom ons delf 'n bietjie dieper in Alvin se argitektuur:

Soms is meer minder. Wanneer las verminder word, lei dit tot toenemende latensie

'n Goeie beginpunt is 'n lys van voltooide I/O-oorgange (netwerkoproepe/skyfopsoeke, ens.). Kom ons probeer uitvind waar die vertraging is. Benewens die ooglopende I/O met die kliënt, neem Alvin 'n ekstra stap: hy kry toegang tot die datastoor. Hierdie berging werk egter in dieselfde groep as Alvin, so die latensie daar moet minder wees as by die kliënt. Dus, die lys van verdagtes:

  1. Netwerkoproep van kliënt na Alvin.
  2. Netwerkoproep van Alvin na die datastoor.
  3. Soek op skyf in die datastoor.
  4. Netwerkoproep van die datapakhuis na Alvin.
  5. Netwerkoproep van Alvin na 'n kliënt.

Kom ons probeer om 'n paar punte deur te trek.

Databerging het niks daarmee te doen nie

Die eerste ding wat ek gedoen het, was om Alvin om te skakel na 'n ping-ping-bediener wat nie versoeke verwerk nie. Wanneer dit 'n versoek ontvang, gee dit 'n leë antwoord. As die latensie afneem, is 'n fout in die implementering van Alvin of datapakhuis niks ongehoord nie. In die eerste eksperiment kry ons die volgende grafiek:

Soms is meer minder. Wanneer las verminder word, lei dit tot toenemende latensie

Soos u kan sien, is daar geen verbetering wanneer u die ping-ping-bediener gebruik nie. Dit beteken dat die datapakhuis nie latensie verhoog nie, en die lys verdagtes word in die helfte gesny:

  1. Netwerkoproep van kliënt na Alvin.
  2. Netwerkoproep van Alvin na 'n kliënt.

Puik! Die lys krimp vinnig. Ek het gedink ek het amper die rede uitgepluis.

gRPC

Dit is nou die tyd om jou aan 'n nuwe speler bekend te stel: gRPC. Dit is 'n oopbron-biblioteek van Google vir in-proses kommunikasie RPC... Alhoewel gRPC goed geoptimaliseer en wyd gebruik, dit was die eerste keer dat ek dit op 'n stelsel van hierdie grootte gebruik het en ek het verwag dat my implementering suboptimaal sou wees - om die minste te sê.

Beskikbaarheid gRPC in die stapel het aanleiding gegee tot 'n nuwe vraag: miskien is dit my implementering of myself gRPC veroorsaak vertragingsprobleem? Voeg 'n nuwe verdagte by die lys:

  1. Die kliënt bel die biblioteek gRPC
  2. Biblioteek gRPC maak 'n netwerkoproep na die biblioteek op die kliënt gRPC op bediener
  3. Biblioteek gRPC kontakte Alvin (geen bewerking in die geval van tafeltennisbediener nie)

Om jou 'n idee te gee van hoe die kode lyk, my kliënt/Alvin-implementering verskil nie veel van die kliënt-bediener nie asynchrone voorbeelde.

Let wel: Bogenoemde lys is 'n bietjie vereenvoudig omdat gRPC maak dit moontlik om jou eie (sjabloon?) inrygmodel te gebruik, waarin die uitvoeringstapel vervleg is gRPC en gebruikersimplementering. Ter wille van eenvoud hou ons by hierdie model.

Profilering sal alles regmaak

Nadat ek die datawinkels deurgehaal het, het ek gedink ek is amper klaar: “Nou is dit maklik! Kom ons pas die profiel toe en vind uit waar die vertraging voorkom.” ek groot aanhanger van presisie profilering, want SVE's is baie vinnig en is meestal nie die bottelnek nie. Die meeste vertragings vind plaas wanneer die verwerker moet ophou verwerk om iets anders te doen. Akkurate CPU-profilering doen presies dit: dit teken alles akkuraat aan konteks skakelaars en maak dit duidelik waar vertragings voorkom.

Ek het vier profiele geneem: met hoë QPS (lae latency) en met 'n tafeltennisbediener met lae QPS (hoë latency), beide aan die kliëntkant en aan die bedienerkant. En net vir ingeval, ek het ook 'n voorbeeldverwerkerprofiel geneem. Wanneer ek profiele vergelyk, soek ek gewoonlik 'n anomalie oproepstapel. Byvoorbeeld, aan die slegte kant met hoë latensie is daar baie meer konteksskakelaars (10 keer of meer). Maar in my geval was die aantal konteksskakelaars amper dieselfde. Tot my afgryse was daar niks betekenisvols daar nie.

Bykomende ontfouting

Ek was desperaat. Ek het nie geweet watter ander gereedskap ek kon gebruik nie, en my volgende plan was in wese om die eksperimente met verskillende variasies te herhaal eerder as om die probleem duidelik te diagnoseer.

Wat as

Van die begin af was ek bekommerd oor die spesifieke 50ms latency. Dit is 'n baie groot tyd. Ek het besluit dat ek stukke uit die kode sal sny totdat ek presies kon uitvind watter deel hierdie fout veroorsaak. Toe kom 'n eksperiment wat gewerk het.

Soos gewoonlik, lyk dit agterna of alles voor die hand liggend was. Ek het die kliënt op dieselfde masjien as Alvin geplaas - en 'n versoek gestuur aan localhost. En die toename in latensie is weg!

Soms is meer minder. Wanneer las verminder word, lei dit tot toenemende latensie

Iets was fout met die netwerk.

Leer netwerkingenieursvaardighede

Ek moet erken: my kennis van netwerktegnologieë is verskriklik, veral as in ag geneem word dat ek elke dag daarmee werk. Maar die netwerk was die hoofverdagte, en ek moes leer hoe om dit te ontfout.

Gelukkig is die internet lief vir diegene wat wil leer. Die kombinasie van ping en tracert het gelyk na 'n goeie begin om netwerkvervoerprobleme te ontfout.

Eerstens het ek begin PsPing na Alvin se TCP-poort. Ek het die verstek instellings gebruik - niks besonders nie. Van meer as 'n duisend pings het nie een 10 ms oorskry nie, met die uitsondering van die eerste een vir opwarming. Dit is in teenstelling met die waargenome toename in latensie van 50 ms by die 99ste persentiel: daar, vir elke 100 versoeke, moes ons ongeveer een versoek met 'n latensie van 50 ms gesien het.

Toe probeer ek tracert: Daar kan 'n probleem wees by een van die nodusse langs die roete tussen Alvin en die kliënt. Maar die spoorsnyer het ook met leë hande teruggekeer.

Dit was dus nie my kode, die gRPC-implementering of die netwerk wat die vertraging veroorsaak het nie. Ek het begin bekommerd raak dat ek dit nooit sou verstaan ​​nie.

Nou met watter OS is ons

gRPC wyd gebruik op Linux, maar eksoties op Windows. Ek het besluit om 'n eksperiment te probeer, wat gewerk het: ek het 'n virtuele Linux-masjien geskep, Alvin vir Linux saamgestel en dit ontplooi.

Soms is meer minder. Wanneer las verminder word, lei dit tot toenemende latensie

En hier is wat gebeur het: die Linux-pingpong-bediener het nie dieselfde vertragings as 'n soortgelyke Windows-gasheer gehad nie, hoewel die databron nie anders was nie. Dit blyk dat die probleem in die gRPC-implementering vir Windows is.

Nagle se algoritme

Al hierdie tyd het ek gedink ek mis 'n vlag gRPC. Nou verstaan ​​ek wat dit regtig is gRPC Windows-vlag ontbreek. Ek het 'n interne RPC-biblioteek gevind waarvan ek seker was dat dit goed sou werk vir alle vlae wat gestel is Winsock. Toe het ek al hierdie vlae by gRPC gevoeg en Alvin op Windows ontplooi, in 'n gelapte Windows tafeltennisbediener!

Soms is meer minder. Wanneer las verminder word, lei dit tot toenemende latensie

byna Klaar: Ek het die bygevoegde vlae een op 'n slag begin verwyder totdat die regressie teruggekeer het sodat ek die oorsaak kon identifiseer. Dit was berug TCP_NODELAY, Nagle se algoritme skakelaar.

Nagle se algoritme poog om die aantal pakkies wat oor 'n netwerk gestuur word te verminder deur die versending van boodskappe te vertraag totdat die pakkiegrootte 'n sekere aantal grepe oorskry. Alhoewel dit vir die gemiddelde gebruiker lekker kan wees, is dit vernietigend vir intydse bedieners, aangesien die bedryfstelsel sommige boodskappe sal vertraag, wat vertragings op lae QPS sal veroorsaak. U gRPC hierdie vlag is in die Linux-implementering vir TCP-sockets gestel, maar nie in Windows nie. Ek is hierdie gekorrigeer.

Gevolgtrekking

Die hoër latensie by lae QPS is veroorsaak deur OS-optimalisering. In retrospek het profilering nie latensie opgespoor nie, want dit is in kernmodus gedoen eerder as in gebruikersmodus. Ek weet nie of Nagle se algoritme deur ETW-opnames waargeneem kan word nie, maar dit sal interessant wees.

Wat die localhost-eksperiment betref, het dit waarskynlik nie aan die werklike netwerkkode geraak nie en Nagle se algoritme het nie gehardloop nie, so die vertragingsprobleme het verdwyn toe die kliënt Alvin deur localhost bereik het.

Die volgende keer as jy 'n toename in latensie sien namate die aantal versoeke per sekonde afneem, behoort Nagle se algoritme op jou lys van verdagtes te wees!

Bron: will.com

Voeg 'n opmerking