Mõnikord on rohkem vähem. Koormuse vähendamine suurendab latentsust

Nagu ka enamik postitusi, on probleem hajutatud teenusega, nimetagem seda teenust Alviniks. Seekord ma ise probleemi ei avastanud, teatasid mulle kliendipoolsed poisid.

Ühel päeval ärkasin Alviniga pikkade viivituste tõttu rahulolematu e-kirja peale, mille plaanisime lähiajal käivitada. Täpsemalt, kliendil oli 99. protsentiili latentsusaeg umbes 50 ms, mis ületab tunduvalt meie latentsuseelarvet. See oli üllatav, kuna testisin teenust ulatuslikult, eriti latentsuse osas, mis on tavaline kaebus.

Enne Alvini katsetamist tegin palju katseid kiirusega 40 10 päringut sekundis (QPS), mis kõik näitasid latentsusaega alla 40 ms. Olin valmis teatama, et ma ei nõustu nende tulemustega. Kuid kirjale veel kord pilgu heites märkasin midagi uut: ma ei olnud täpselt testinud nende mainitud tingimusi, nende QPS oli palju madalam kui minu oma. Testisin 1k QPS-iga, aga nemad ainult XNUMXk. Tegin veel ühe katse, seekord madalama QPS-iga, et neid rahustada.

Kuna ma sellest blogis kirjutan, olete ilmselt juba aru saanud, et nende numbrid olid õiged. Testisin oma virtuaalklienti ikka ja jälle, sama tulemusega: väike päringute arv mitte ainult ei suurenda latentsust, vaid suurendab ka taotluste arvu, mille latentsusaeg on üle 10 ms. Teisisõnu, kui 40k QPS-i juures ületas umbes 50 päringut sekundis 50 ms, siis 1k QPS-i puhul oli igas sekundis 100 päringut üle 50 ms. Paradoks!

Mõnikord on rohkem vähem. Koormuse vähendamine suurendab latentsust

Otsingu kitsendamine

Kui seisate silmitsi latentsusprobleemiga paljude komponentidega hajutatud süsteemis, on esimene samm kahtlusaluste lühikese loendi koostamine. Kaevume Alvini arhitektuuri veidi sügavamale:

Mõnikord on rohkem vähem. Koormuse vähendamine suurendab latentsust

Hea lähtepunkt on lõpetatud I/O üleminekute loend (võrgukõned/kettaotsingud jne). Proovime välja mõelda, kus on viivitus. Lisaks ilmselgele I/O-le kliendiga astub Alvin lisasammu: ta siseneb andmesalve. See salvestusruum töötab aga Alviniga samas klastris, nii et latentsusaeg peaks seal olema väiksem kui kliendil. Niisiis, kahtlusaluste nimekiri:

  1. Võrgukõne kliendilt Alvinile.
  2. Võrgukõne Alvinilt andmesalve.
  3. Otsige andmesalves kettalt.
  4. Võrgukõne andmelaost Alvinile.
  5. Võrgukõne Alvinilt kliendile.

Proovime mõned punktid maha kriipsutada.

Andmete salvestamisel pole sellega midagi pistmist

Esimese asjana teisendasin Alvini ping-ping serveriks, mis taotlusi ei töötle. Kui ta saab päringu, tagastab see tühja vastuse. Kui latentsusaeg väheneb, pole viga Alvini või andmelao teostuses midagi ennekuulmatut. Esimeses katses saame järgmise graafiku:

Mõnikord on rohkem vähem. Koormuse vähendamine suurendab latentsust

Nagu näete, pole ping-pingi serveri kasutamisel mingit paranemist. See tähendab, et andmeladu ei suurenda latentsust ja kahtlusaluste nimekiri väheneb poole võrra:

  1. Võrgukõne kliendilt Alvinile.
  2. Võrgukõne Alvinilt kliendile.

Suurepärane! Nimekiri kahaneb kiiresti. Arvasin, et olen põhjuse peaaegu aru saanud.

gRPC

Nüüd on aeg tutvustada teile uut mängijat: gRPC. See on Google'i avatud lähtekoodiga teek protsessisiseseks suhtluseks RPC... Kuigi gRPC hästi optimeeritud ja laialdaselt kasutatav, kasutasin seda esimest korda sellise suurusega süsteemis ja eeldasin, et minu rakendamine on pehmelt öeldes ebaoptimaalne.

kättesaadavus gRPC virnas tekitas uue küsimuse: võib-olla on see minu teostus või mina ise gRPC põhjustab latentsusprobleemi? Uue kahtlusaluse lisamine nimekirja:

  1. Klient helistab raamatukokku gRPC
  2. raamatukogu gRPC teeb võrgukõne kliendil raamatukogusse gRPC serveris
  3. raamatukogu gRPC võtab ühendust Alviniga (ping-pongi serveri puhul ei toimi)

Et anda teile aimu, kuidas kood välja näeb, ei erine minu kliendi/Alvini juurutamine palju klient-serveri rakendustest asünkroonsed näited.

Märkus. Ülaltoodud loend on veidi lihtsustatud, kuna gRPC võimaldab kasutada enda (malli?) lõimestamise mudelit, milles on läbi põimunud täitmispinn gRPC ja kasutaja rakendamine. Lihtsuse huvides jääme selle mudeli juurde.

Profileerimine parandab kõik

Olles andmesalved läbi kriipsutanud, arvasin, et olen peaaegu valmis: „Nüüd on see lihtne! Rakendame profiili ja uurime välja, kus viivitus ilmneb. I täppisprofiilide suur fänn, sest protsessorid on väga kiired ja enamasti ei ole need kitsaskohad. Enamik viivitusi tekib siis, kui protsessor peab töötlemise lõpetama, et midagi muud teha. Täpne CPU profileerimine teeb just seda: see salvestab kõik täpselt konteksti lülitid ja teeb selgeks, kus esinevad viivitused.

Võtsin neli profiili: kõrge QPS-iga (madal latentsusaeg) ja madala QPS-iga (kõrge latentsusaeg) ping-pongi serveriga, nii kliendi kui ka serveri poolel. Ja igaks juhuks võtsin ka prooviprotsessori profiili. Profiilide võrdlemisel otsin tavaliselt anomaalset kõnepinu. Näiteks suure latentsusajaga halva poole pealt on palju rohkem kontekstilüliteid (10 korda või rohkem). Kuid minu puhul oli kontekstilülitite arv peaaegu sama. Minu õuduseks polnud seal midagi märkimisväärset.

Täiendav silumine

Ma olin meeleheitel. Ma ei teadnud, milliseid muid tööriistu saan kasutada, ja minu järgmine plaan oli sisuliselt korrata katseid erinevate variatsioonidega, mitte probleemi selgelt diagnoosida.

Mis siis kui

Algusest peale muretsesin konkreetse 50 ms latentsuse pärast. See on väga suur aeg. Otsustasin, et lõikan koodist tükke, kuni saan täpselt aru, milline osa selle vea põhjustas. Siis tuli katse, mis töötas.

Nagu ikka, tundub tagantjärele, et kõik oli ilmselge. Panin kliendi Alviniga samasse masinasse – ja saatsin päringu aadressile localhost. Ja latentsusaja suurenemine on kadunud!

Mõnikord on rohkem vähem. Koormuse vähendamine suurendab latentsust

Midagi oli võrguga valesti.

Võrguinseneri oskuste õppimine

Pean tunnistama: minu teadmised võrgutehnoloogiatest on kohutavad, eriti arvestades asjaolu, et töötan nendega iga päev. Kuid võrk oli peamine kahtlusalune ja ma pidin õppima, kuidas seda siluda.

Õnneks Internet armastab neid, kes tahavad õppida. Pingi ja tracerti kombinatsioon tundus olevat piisavalt hea algus võrgu transpordiprobleemide silumiseks.

Esiteks käivitasin PsPing Alvini TCP-porti. Kasutasin vaikesätteid – ei midagi erilist. Rohkem kui tuhandest pingist ei ületanud ükski 10 ms, välja arvatud esimene soojenduseks. See on vastuolus täheldatud latentsusaja suurenemisega 50 ms 99. protsentiili juures: seal oleksime pidanud iga 100 päringu kohta nägema umbes ühte 50 ms latentsusajaga päringut.

Siis ma proovisin tracert: Alvini ja kliendi vahelise marsruudi ühes sõlmes võib olla probleem. Kuid ka jälitaja naasis tühjade kätega.

Nii et viivitust ei põhjustanud minu kood, gRPC rakendus ega võrk. Ma hakkasin muretsema, et ma ei saa sellest kunagi aru.

Mis operatsioonisüsteemi me nüüd kasutame

gRPC Linuxis laialdaselt kasutatav, kuid Windowsis eksootiline. Otsustasin proovida katset, mis töötas: lõin Linuxi virtuaalmasina, kompileerisin Alvini Linuxi jaoks ja juurutasin selle.

Mõnikord on rohkem vähem. Koormuse vähendamine suurendab latentsust

Ja juhtus järgmine: Linuxi pingpongiserveril ei olnud samasuguseid viivitusi kui sarnasel Windowsi hostil, kuigi andmeallikas ei erinenud. Selgub, et probleem on Windowsi gRPC-rakenduses.

Nagle algoritm

Kogu selle aja arvasin, et mul on lipp puudu gRPC. Nüüd ma saan aru, mis see tegelikult on gRPC Windowsi lipp puudub. Leidsin sisemise RPC teegi, mis oleks kindel, et see toimiks hästi kõigi seatud lippude jaoks Winsock. Seejärel lisasin kõik need lipud gRPC-sse ja juurutasin Alvini Windowsis, paigatud Windowsi pingpongiserveris!

Mõnikord on rohkem vähem. Koormuse vähendamine suurendab latentsust

Peaaegu Valmis: hakkasin lisatud lippe ükshaaval eemaldama, kuni regressioon taastus, et saaksin põhjuse täpselt kindlaks teha. See oli kurikuulus TCP_NODELAY, Nagle'i algoritmi lüliti.

Nagle algoritm püüab vähendada võrgu kaudu saadetavate pakettide arvu, lükates sõnumite edastamise edasi, kuni paketi suurus ületab teatud arvu baite. Kuigi see võib olla tavakasutaja jaoks tore, on see reaalajas serverite jaoks hävitav, kuna OS lükkab mõned sõnumid edasi, põhjustades viivitusi madalal QPS-il. U gRPC see lipp määrati Linuxi teostuses TCP-pesade jaoks, kuid mitte Windowsis. Mina olen see parandatud.

Järeldus

Suurem latentsus madala QPS-i korral oli tingitud OS-i optimeerimisest. Tagantjärele ei tuvastanud profiilide koostamine latentsust, kuna seda tehti pigem kerneli režiimis kui sees kasutaja režiim. Ma ei tea, kas Nagle algoritmi saab ETW jäädvustamise kaudu jälgida, kuid see oleks huvitav.

Mis puutub localhosti katsesse, siis see tõenäoliselt ei puudutanud tegelikku võrgukoodi ja Nagle algoritm ei töötanud, nii et latentsusprobleemid kadusid, kui klient jõudis localhosti kaudu Alvini.

Järgmine kord, kui märkate latentsusaja pikenemist, kui päringute arv sekundis väheneb, peaks Nagle'i algoritm olema teie kahtlusaluste nimekirjas!

Allikas: www.habr.com

Lisa kommentaar