Joskus enemmän on vähemmän. Kuorman vähentäminen lisää latenssia

Kuten useimmat viestit, hajautetun palvelun kanssa on ongelma, kutsutaan tätä palvelua Alviniksi. Tällä kertaa en havainnut ongelmaa itse, asiakaspuolen kaverit kertoivat minulle.

Eräänä päivänä heräsin tyytymättömään sähköpostiin, joka johtui pitkistä viiveistä Alvinin kanssa, jonka aioimme julkaista lähitulevaisuudessa. Tarkemmin sanottuna asiakas koki 99. prosenttipisteen latenssin noin 50 ms:n alueella, mikä on selvästi yli viivebudjettimme. Tämä oli yllättävää, koska testasin palvelua laajasti, etenkin latenssin suhteen, mikä on yleinen valitus.

Ennen kuin laitoin Alvinin testaukseen, tein paljon kokeita 40 10 kyselyllä sekunnissa (QPS), jotka kaikki osoittivat alle 40 ms latenssia. Olin valmis ilmoittamaan, että en ole samaa mieltä heidän tuloksistaan. Mutta kun katsoin kirjettä uudelleen, huomasin jotain uutta: en ollut tarkalleen testannut heidän mainitsemiaan olosuhteita, heidän QPS:nsä oli paljon alhaisempi kuin minun. Testasin 1k QPS:llä, mutta he vain XNUMXk:lla. Tein toisen kokeen, tällä kertaa alhaisemmalla QPS:llä, vain rauhoitellakseni heitä.

Koska bloggaan tästä, olet luultavasti jo tajunnut, että heidän numeronsa olivat oikein. Testasin virtuaaliasiakkaani uudestaan ​​​​ja uudestaan, ja sama tulos: pieni pyyntöjen määrä ei vain lisää viivettä, vaan lisää pyyntöjen määrää, joiden latenssi on yli 10 ms. Toisin sanoen, jos 40k QPS:llä noin 50 pyyntöä sekunnissa ylitti 50 ms, niin 1k QPS:llä oli 100 yli 50 ms pyyntöä sekunnissa. Paradoksi!

Joskus enemmän on vähemmän. Kuorman vähentäminen lisää latenssia

Haun rajaaminen

Kun kohtaat latenssiongelman hajautetussa järjestelmässä, jossa on monia komponentteja, ensimmäinen askel on luoda lyhyt luettelo epäillyistä. Kaivataanpa hieman syvemmälle Alvinin arkkitehtuuria:

Joskus enemmän on vähemmän. Kuorman vähentäminen lisää latenssia

Hyvä aloituskohta on luettelo suoritetuista I/O-siirtymistä (verkkopuhelut/levyhaut jne.). Yritetään selvittää, missä viive on. Asiakkaan kanssa tehtävän ilmeisen I/O:n lisäksi Alvin ottaa ylimääräisen askeleen: hän käyttää tietovarastoa. Tämä tallennustila toimii kuitenkin samassa klusterissa kuin Alvin, joten latenssin pitäisi olla pienempi kuin asiakkaan kanssa. Eli lista epäillyistä:

  1. Verkkopuhelu asiakkaalta Alvinille.
  2. Verkkopuhelu Alvinilta tietovarastoon.
  3. Hae levyltä tietovarastosta.
  4. Verkkopuhelu tietovarastosta Alvinille.
  5. Verkkopuhelu Alvinilta asiakkaalle.

Yritetään yliviivata joitakin kohtia.

Tietojen tallennuksella ei ole mitään tekemistä sen kanssa

Ensimmäinen asia, jonka tein, oli muuntaa Alvin ping-ping-palvelimeksi, joka ei käsittele pyyntöjä. Kun se vastaanottaa pyynnön, se palauttaa tyhjän vastauksen. Jos latenssi pienenee, Alvin- tai tietovarasto-toteutuksen bugi ei ole ennenkuulumatonta. Ensimmäisessä kokeessa saamme seuraavan kaavion:

Joskus enemmän on vähemmän. Kuorman vähentäminen lisää latenssia

Kuten näet, ping-ping-palvelinta käytettäessä ei ole parannusta. Tämä tarkoittaa, että tietovarasto ei lisää latenssia ja epäiltyjen lista puolittuu:

  1. Verkkopuhelu asiakkaalta Alvinille.
  2. Verkkopuhelu Alvinilta asiakkaalle.

Loistava! Lista kutistuu nopeasti. Luulin jo melkein ymmärtäneeni syyn.

gRPC

Nyt on aika esitellä sinulle uusi pelaaja: gRPC. Tämä on Googlen avoimen lähdekoodin kirjasto prosessin aikana tapahtuvaa viestintää varten RPC. vaikka gRPC hyvin optimoitu ja laajalti käytetty, tämä oli ensimmäinen kerta, kun käytin sitä tämän kokoisessa järjestelmässä, ja odotin toteutukseni olevan alle optimaalisen - vähintäänkin.

saatavuus gRPC pinossa herätti uuden kysymyksen: ehkä se on minun toteutukseni tai minä gRPC aiheuttaa latenssiongelmaa? Uuden epäillyn lisääminen listalle:

  1. Asiakas soittaa kirjastoon gRPC
  2. kirjasto gRPC soittaa verkkopuhelun asiakkaan kirjastoon gRPC palvelimella
  3. kirjasto gRPC ottaa yhteyttä Alviniin (ei toimintaa ping-pong-palvelimen tapauksessa)

Jotta saat käsityksen siitä, miltä koodi näyttää, asiakas/Alvin-toteutukseni ei eroa paljoakaan asiakas-palvelin toteutuksista. asynkronisia esimerkkejä.

Huomautus: Yllä oleva luettelo on hieman yksinkertaistettu, koska gRPC mahdollistaa oman (mallin?) ketjutusmallin käytön, jossa suorituspino on kietoutunut yhteen gRPC ja käyttäjätoteutus. Yksinkertaisuuden vuoksi pysymme tässä mallissa.

Profilointi korjaa kaiken

Yliviivattuani tietovarastot ajattelin olevani melkein valmis: ”Nyt se on helppoa! Otetaan profiili käyttöön ja selvitetään, missä viive tapahtuu." minä suuri tarkkuusprofiloinnin fani, koska prosessorit ovat erittäin nopeita eivätkä useimmiten ole pullonkaula. Useimmat viiveet tapahtuvat, kun prosessorin on lopetettava käsittely tehdäkseen jotain muuta. Tarkka CPU Profiling tekee juuri sen: se tallentaa tarkasti kaiken kontekstin kytkimet ja tekee selväksi, missä viivästyksiä esiintyy.

Otin neljä profiilia: korkealla QPS:llä (alhainen latenssi) ja ping-pong-palvelimella, jolla on matala QPS (korkea latenssi), sekä asiakas- että palvelinpuolella. Ja varmuuden vuoksi otin myös näyteprosessoriprofiilin. Profiilien vertailussa etsin yleensä poikkeavaa puhelupinoa. Esimerkiksi huonolla puolella korkealla viiveellä on paljon enemmän kontekstikytkimiä (10 kertaa tai enemmän). Mutta minun tapauksessani kontekstikytkimien määrä oli melkein sama. Minun kauhuksi siellä ei ollut mitään merkittävää.

Lisävirheenkorjaus

Olin epätoivoinen. En tiennyt, mitä muita työkaluja voisin käyttää, ja seuraava suunnitelmani oli lähinnä toistaa kokeet eri muunnelmilla sen sijaan, että diagnosoisin ongelman selkeästi.

Mitä jos

Alusta alkaen olin huolissani tietystä 50 ms latenssista. Tämä on erittäin suurta aikaa. Päätin leikata koodista paloja, kunnes saan selville, mikä osa aiheutti tämän virheen. Sitten tuli kokeilu, joka toimi.

Kuten tavallista, jälkeenpäin ajateltuna näyttää siltä, ​​että kaikki oli itsestään selvää. Laitoin asiakkaan samalle koneelle kuin Alvin - ja lähetin pyynnön localhost. Ja latenssin kasvu on poissa!

Joskus enemmän on vähemmän. Kuorman vähentäminen lisää latenssia

Jotain oli vialla verkossa.

Verkkoinsinööritaitojen oppiminen

Minun on myönnettävä: tietoni verkkoteknologioista on kauhea, varsinkin kun ottaa huomioon sen, että työskentelen niiden kanssa päivittäin. Mutta verkko oli pääepäilty, ja minun piti oppia korjaamaan se.

Onneksi Internet rakastaa niitä, jotka haluavat oppia. Pingin ja tracertin yhdistelmä vaikutti riittävän hyvältä alusta verkon kuljetusongelmien virheenkorjaukseen.

Ensin käynnistin PsPing Alvinin TCP-porttiin. Käytin oletusasetuksia - ei mitään erikoista. Yli tuhannesta pingistä yksikään ei ylittänyt 10 ms, lukuun ottamatta ensimmäistä lämmittelyä varten. Tämä on vastoin havaittua 50 ms:n viiveen kasvua 99. prosenttipisteessä: siellä jokaista 100 pyyntöä kohden meidän olisi pitänyt nähdä noin yksi pyyntö, jonka latenssi on 50 ms.

Sitten yritin tracert: Yhdessä Alvinin ja asiakkaan välisen reitin solmussa voi olla ongelma. Mutta jäljittäjä palasi myös tyhjin käsin.

Joten se ei ollut minun koodini, gRPC-toteutus tai verkko, joka aiheutti viiveen. Aloin pelätä, etten koskaan ymmärtäisi tätä.

Mikä käyttöjärjestelmä meillä nyt on

gRPC laajalti käytetty Linuxissa, mutta eksoottinen Windowsissa. Päätin kokeilla kokeilua, joka toimi: loin Linux-virtuaalikoneen, käänsin Alvinin Linuxille ja otin sen käyttöön.

Joskus enemmän on vähemmän. Kuorman vähentäminen lisää latenssia

Ja tässä tapahtui: Linuxin ping-pong-palvelimella ei ollut samoja viiveitä kuin vastaavalla Windows-isännällä, vaikka tietolähde ei ollutkaan erilainen. Osoittautuu, että ongelma on Windowsin gRPC-toteutuksessa.

Naglen algoritmi

Koko tämän ajan luulin, että minulta puuttuu lippu gRPC. Nyt ymmärrän mitä se oikeasti on gRPC Windows-lippu puuttuu. Löysin sisäisen RPC-kirjaston, jonka olin varma, että se toimisi hyvin kaikille lipuille Winsock. Sitten lisäsin kaikki nämä liput gRPC:hen ja otin Alvinin käyttöön Windowsissa korjatussa Windowsin ping-pong-palvelimessa!

Joskus enemmän on vähemmän. Kuorman vähentäminen lisää latenssia

melkein Valmis: Aloin poistaa lisättyjä lippuja yksi kerrallaan, kunnes regressio palasi, jotta pystyin paikantamaan syyn. Se oli surullisen kuuluisaa TCP_NODELAY, Naglen algoritmikytkin.

Naglen algoritmi yrittää vähentää verkon kautta lähetettyjen pakettien määrää viivyttämällä viestien lähetystä, kunnes paketin koko ylittää tietyn tavumäärän. Vaikka tämä voi olla mukavaa tavalliselle käyttäjälle, se on tuhoisaa reaaliaikaisille palvelimille, koska käyttöjärjestelmä viivästyttää joitakin viestejä, mikä aiheuttaa viiveitä alhaisessa QPS: ssä. U gRPC tämä lippu on asetettu TCP-socketin Linux-toteutuksessa, mutta ei Windowsissa. Minä olen tämä korjattu.

Johtopäätös

Korkeampi latenssi alhaisella QPS:llä johtui käyttöjärjestelmän optimoinnista. Jälkikäteen tarkasteltuna profilointi ei havainnut latenssia, koska se tehtiin ydintilassa eikä sisään käyttäjätila. En tiedä, voidaanko Naglen algoritmia tarkkailla ETW-kaappausten kautta, mutta se olisi mielenkiintoista.

Mitä tulee localhost-kokeiluon, se ei luultavasti koskenut varsinaiseen verkkokoodiin ja Naglen algoritmi ei toiminut, joten latenssiongelmat poistuivat, kun asiakas tavoitti Alvinin localhostin kautta.

Kun seuraavan kerran huomaat viiveen lisääntyvän, kun pyyntöjen määrä sekunnissa vähenee, Naglen algoritmin pitäisi olla epäiltyjen luettelossasi!

Lähde: will.com

Lisää kommentti