Kuka siirsi 99. prosentin latenssini?

Co-author: Cuong Tran

Pitkät viiveet vaikuttavat jäseniin joka päivä, ja järjestelmien vasteaikojen parantaminen jopa 99. prosenttipisteessä on ratkaisevan tärkeää jäsenten kokemuksen kannalta. Syitä voi olla monia, kuten hitaat sovellukset, hitaat levykäynnit, verkkovirheet ja monet muut. Olemme törmänneet mikropurkautuvan liikenteen perimmäiseen syyhyn, jota ei voida helposti ratkaista suojautumisstrategialla, eli lähettämällä sama pyyntö usealle palvelimelle siinä toivossa, että yksi palvelimista ei kärsi pitkistä viiveistä. Tässä seuraavassa postauksessa kerromme menetelmästä, jolla selvitämme pitkien latenssiviiveiden perimmäisen syyn, kokemuksistamme ja opetuksistamme.

Datakeskuksen sisällä olevien koneiden väliset verkkoviiveet voivat olla alhaisia. Yleensä kaikki viestintä kestää muutaman mikrosekunnin, mutta silloin tällöin joillakin paketeilla kestää muutaman millisekunnin. Muutaman millisekunnin kestävät paketit kuuluvat yleensä latenssien 90. persentiiliin tai sitä korkeampaan. Pitkähäntäiset viiveet syntyvät, kun näiden korkeiden prosenttiosuuksien arvot alkavat ylittää selvästi keskiarvon ja voivat olla suuruusluokkaa suurempia kuin keskiarvo. Näin ollen keskimääräiset viiveet kertovat vain puolet tarinasta. Alla olevasta kuvaajasta näkyy ero hyvän ja pitkähäntäisen latenssijakauman välillä. Kuten näet, 99. persentiili on 30 kertaa huonompi kuin mediaani ja 99,9 persentiili on 50 kertaa huonompi!

Pituushännillä on todella väliä!

30 ms:n 99. persentiili tarkoittaa, että joka sadas pyyntö kokee 30 ms:n viiveen. LinkedInin kaltaisella vilkkaasti liikennöidyllä verkkosivustolla tämä voi tarkoittaa, että sivulla, jolla on 1 miljoona sivulatausta päivässä, 10 000 näistä sivulatauksista kokee viiveen. Useimmat järjestelmät ovat kuitenkin nykyään hajautettuja järjestelmiä, ja yksi pyyntö voi itse asiassa luoda useita myöhempiä pyyntöjä. Yksi pyyntö voi siis synnyttää 2 pyyntöä tai 10 tai jopa 100 pyyntöä! Jos useat alaspäin suuntautuvat pyynnöt osuvat yhteen palveluun, johon kohdistuu pitkähäntäviive, ongelmamme muuttuu pelottavammaksi.

Kuvituksena sanotaan, että 1 asiakaspyyntö luo 10 alaspäin suuntautuvaa pyyntöä alaspäin suuntautuvaan osajärjestelmään, johon kohdistuu pitkähäntäviive. Ja oletetaan, että sillä on 1 % todennäköisyys vastata hitaasti yhteen pyyntöön. Tällöin todennäköisyys sille, että ainakin 1 10:stä downstream-pyynnöstä kärsii longtail-viiveistä, vastaa kaikkien downstream-pyyntöjen nopean vastaamisen komplementtia (99 prosentin todennäköisyys vastata nopeasti mihin tahansa yksittäiseen pyyntöön), joka on:

Se on 9,5 prosenttia! Tämä tarkoittaa, että 1 asiakaspyynnön kohdalla on lähes 10 prosentin todennäköisyys joutua hitaan vastauksen kohteeksi. Tämä vastaa sitä, että 1 miljoonasta asiakaspyynnöstä 100 000 asiakaspyyntöön odotetaan vaikuttavan. Se on paljon jäseniä!

Edellisessä esimerkissämme ei kuitenkaan oteta huomioon sitä, että aktiiviset jäsenet selaavat yleensä useampaa kuin yhtä sivua, ja jos yksittäinen käyttäjä tekee saman asiakaspyynnön useita kertoja, todennäköisyys sille, että viiveongelmat vaikuttavat käyttäjään, kasvaa dramaattisesti. Näin ollen hyvin aktiivisella taustapalvelulla, johon pitkät latenssiviiveet vaikuttavat, voi olla vakavia vaikutuksia koko sivuston laajuisesti.

Tapaustutkimus

Viime aikoina meillä oli tilaisuus tutkia yhtä hajautettua järjestelmäämme, jossa esiintyi pitkiä verkkoviiveitä. Ongelma oli piileksinyt muutaman kuukauden ajan, eikä pintapuolisissa tutkimuksissa ollut havaittavissa mitään ilmeistä syytä pitkiin verkkoviiveisiin. Päätimme tehdä perusteellisemman tutkimuksen ongelman perimmäisen syyn selvittämiseksi. Tässä blogikirjoituksessa halusimme jakaa kokemuksemme ja menetelmän, jota käytimme perimmäisen syyn selvittämiseen seuraavan tapaustutkimuksen avulla.

Vaihe 1: Hallittu ja yksinkertaistettu ympäristö

Aluksi perustimme testiympäristön todellisesta tuotantojärjestelmästä. Yksinkertaistimme järjestelmän muutamaan koneeseen, jotka pystyivät toistamaan verkon pitkät latenssit. Lisäksi sammutimme loggauksen ja pysyvyysvälimuistitiedon levyllä IO-stressin poistamiseksi. Näin pystyimme keskittymään keskeisiin komponentteihin, kuten suorittimeen ja verkkoon. Muokkasimme myös simuloituja liikennesuoritteita, jotka pystyimme toistamaan, jotta saimme toistettavia testejä, kun teimme kokeita ja virityksiä järjestelmissä. Alla olevassa kaaviossa näkyy testiympäristömme, joka koostui API-kerroksesta, välimuistipalvelimesta ja pienestä tietokantaklusterista.

Korkealla tasolla ulkoisten palveluiden pyynnöt tulevat hajautettuun järjestelmään API-kerroksen kautta. Tämän jälkeen pyynnöt tehdään välimuistipalvelimelle kyselyjen täyttämiseksi. Jos tietoja ei ole välimuistissa, välimuistipalvelin tekee tietokantaklusterille pyyntöjä kyselyvastauksen muodostamiseksi.

Vaihe 2: Mittaa päästä-päähän-viive

Seuraavaksi tarkasteltiin yksityiskohtaisia päästä-päähän-viiveitä. Näin pystyimme yrittämään eristää pitkät latenssit ja näkemään, mikä hajautetun järjestelmämme komponentti vaikutti havaittuihin latensseihin. Simuloidun liikenneajon aikana käytimme ping-apuohjelmaa API-kerroksen isännän, välimuistipalvelimen isännän ja yhden tietokantaklusterin isännän välisten eri parien välillä latenssien mittaamiseksi. Seuraavassa näkyvät isäntäparin väliset 99. prosenttipisteen latenssit:

Näistä alustavista mittauksista päättelimme, että välimuistipalvelimella oli pitkien latenssien ongelma. Teimme lisää kokeita näiden havaintojen todentamiseksi ja havaitsimme seuraavaa:

  1. Suurimpana ongelmana olivat 99. prosenttipisteen latenssit välimuistipalvelimelle saapuvassa liikenteessä.
  2. 99. prosenttipisteen latenssit mitattiin muihin isäntäkoneisiin, jotka sijaitsivat samassa telineessä kuin välimuistipalvelin, eivätkä muut isännät kärsineet.
  3. 99. prosenttipisteen viiveet mitattiin myös TCP-, UDP- ja ICMP-liikenteellä, ja kaikki välimuistipalvelimelle saapuva liikenne vaikutti.

Seuraavaksi purettiin epäillyn välimuistipalvelimen verkko- ja protokollapino. Näin toivoimme voivamme eristää sen osan välimuistipalvelimesta, joka vaikutti longtail-viiveisiin. Päästä-päähän-erittelyn latenssimittauksemme on esitetty alla:

Toteutimme nämä mittaukset toteuttamalla yksinkertaisen UDP request/response -sovelluksen C-kielellä ja käytimme Linux-järjestelmän tarjoamaa aikaleimausta verkkoliikenteeseen. Ytimen dokumentaatiossa on esimerkki timestamping.c:n ominaisuuksista, joiden avulla saat yksityiskohtaista tietoa siitä, milloin paketit osuivat verkkokortille ja pistorasioihin. On myös syytä huomata, että jotkin verkkokortit tarjoavat laitteiston aikaleimauksen, jonka avulla voit saada tietoa siitä, milloin paketit todella kulkevat verkkokortin läpi; kaikki kortit eivät kuitenkaan tue tätä. Lisätietoja on tässä RedHatin asiakirjassa. Käytimme järjestelmässä myös tcpdumpsia voidaksemme nähdä, milloin käyttöjärjestelmä käsittelee pyynnöt/vastaukset protokollatasolla.

Vaihe 3: eliminoi ja kokeile

Sen jälkeen, kun olimme todenneet, että viiveongelma johtui verkkokortin laitteiston ja käyttöjärjestelmän protokollakerroksen välisestä viiveestä, keskityimme vahvasti näihin järjestelmän osiin. Koska verkkokortti (NIC) saattoi olla mahdollinen ongelma, päätimme tutkia sen ensin ja edetä pinoissa ylöspäin eliminoidaksemme eri kerrokset. Tarkastellessamme kutakin komponenttia pidimme mielessä seuraavat asiat: Fairness, Contentions ja Saturation. Nämä kolme avainaluetta auttavat löytämään mahdolliset pullonkaulat tai viiveongelmat.

  • Fairness: Saavatko järjestelmän yksiköt oikeudenmukaisen osuuden ajasta tai resursseista käsittelyyn tai loppuunsaattamiseen? Saavatko esimerkiksi kaikki järjestelmän sovellukset oikeudenmukaisen määrän aikaa suorittimien suorittamiseen, jotta ne voivat suorittaa tehtävänsä? Jos näin ei ole, aiheuttaako epäoikeudenmukaisuus tai oikeudenmukaisuus ongelmia? Ehkä esimerkiksi jotakin ensisijaista sovellusta pitäisi suosia muiden kustannuksella; reaaliaikaisen videon käsittely vaatii enemmän aikaa kuin taustatyö, jonka avulla voit varmuuskopioida tiedostoja pilvipalveluun.
  • Contentions: Taistelevatko järjestelmässä olevat entiteetit samasta resurssista? Jos esimerkiksi kaksi sovellusta kirjoittaa yhdelle kiintolevylle, molempien sovellusten on kilpailtava aseman kaistanleveydestä. Tämä liittyy vahvasti oikeudenmukaisuuteen, sillä riidat on ratkaistava jonkinlaisella oikeudenmukaisuusalgoritmilla. Riitoja voi olla helpompi etsiä kuin oikeudenmukaisuuskysymystä.
  • Saturation: Onko resurssi yli- tai kokonaan käytössä? Jos resurssi on ylikäytössä tai kokonaan käytössä, saatamme törmätä johonkin rajoitukseen, joka aiheuttaa riitoja tai viiveitä, kun yksiköt joutuvat jonottamaan resurssien käyttöön sitä mukaa kuin niitä vapautuu.

Käsitellessämme verkkokorttia keskityimme pääasiassa tarkastelemaan a) onko jonoja ylikuormitettu, mikä näkyisi hylkäämisinä ja osoittaisi mahdollisia kaistanleveyden käyttörajoituksia, tai b) oliko olemassa epämuodostuneita paketteja, jotka tarvitsivat uudelleenlähetyksiä, mikä voisi aiheuttaa viiveitä. Kokeidemme aikana verkkokorttiin osui 0 hylättyä ja 0 epämuodostunutta pakettia, ja kaistanleveyden käyttö oli noin 5-40 MB/s, mikä on vähän 1 Gbps:n laitteistollamme.

Seuraavaksi keskityimme ajuri- ja protokollatasoon. Näitä kahta osaa oli vaikea erottaa toisistaan; käytimme kuitenkin suuren osan tutkimuksestamme tarkastelemalla erilaisia käyttöjärjestelmän virityksiä, jotka käsittelivät prosessien ajoitusta, ytimien resurssien käyttöä, keskeytysten käsittelyn ajoitusta ja keskeytysaffiniteettia ytimien käytön kannalta. Nämä keskeiset osa-alueet voivat mahdollisesti aiheuttaa viiveitä verkkopakettien käsittelyssä, ja halusimme varmistaa, että pyynnöt ja vastaukset käsitellään niin nopeasti kuin kone pystyy käsittelemään. Valitettavasti suurin osa kokeiluistamme ei tuottanut mitään perimmäistä syytä.

Alussa havaitsemamme oireet näyttivät viittaavan kaistanleveyden rajoittuneeseen järjestelmään. Kun liikennettä syntyy paljon, viiveet kasvavat jonotusviiveiden vuoksi. Kun kuitenkin tarkastelimme verkkokorttikerrosta, emme nähneet tällaista ongelmaa. Mutta kun olimme poistaneet lähes kaiken pinoista, tajusimme, että suorituskykymittarimme mittaavat yhden sekunnin tai 1 000 millisekunnin tarkkuudella. Kun viivettä on 30 ms, miten voisimme mitenkään toivoa saavamme ongelman selville?

Microburstit, voi sentään!

Monissa järjestelmissämme on 1 Gbps:n verkkokortteja. Kun tarkastelimme saapuvaa liikennettä, huomasimme, että Cache-palvelimella oli yleensä 5 – 40 MB/s liikennettä. Tällainen kaistanleveyden käyttö ei herätä mitään punaisia lippuja; mutta entä jos katsoisimme kaistanleveyden käyttöä millisekunnissa! Ensimmäinen alla oleva kaavio kuvaa kaistanleveyden käyttöä sekunnissa ja osoittaa vähäistä käyttöä, kun taas toinen kaavio kuvaa kaistanleveyden käyttöä millisekunnissa ja osoittaa aivan toisenlaisen tarinan.

Mittaaksemme millisekunnissa tulevaa kaistanleveysliikennettä käytimme tcpdumpia kerätäksemme liikennettä määrätyn ajanjakson ajan. Tämä vaati offline-laskelmia, mutta koska tcpdumpeissa on mikrosekuntitason aikaleimat, pystyimme laskemaan saapuvan kaistanleveyden käytön millisekuntia kohden. Näiden mittausten avulla pystyimme tunnistamaan syyn verkon pitkiin viiveisiin. Kuten yllä olevista kaavioista näkyy, kaistanleveyden käyttö millisekuntia kohti osoittaa lyhyitä, muutaman sadan millisekunnin pituisia jaksoja, jotka ovat lähes 100 kB/ms. Tällainen koko sekunnin ajan jatkuva 100 kB/ms vastaa 100 MB/s, mikä on 80 prosenttia 1 Gbps:n verkkokorttien teoreettisesta kapasiteetista! Näitä purskeita kutsutaan mikropurkauksiksi, ja ne syntyvät siitä, että hajautettu tietokantaklusteri vastaa välimuistipalvelimelle kerralla, jolloin linkki on täydessä käytössä alle sekunnin ajan. Alla on kaavio kaistanleveyden käytöstä prosentteina 1 Gbps:n nopeuksista verrattuna saman ajanjakson aikana mitattuihin latensseihin. Kuten näet, latenssipiikkien ja purskeisen liikenteen välillä on suuri korrelaatio:

Nämä kuvaajat osoittavat alisekunnin mittausten tärkeyden! Vaikka täydellistä infrastruktuuria on vaikea ylläpitää tällaisella datalla, ainakin syvällisiä tutkimuksia varten sen pitäisi olla go to granulariteetti, koska suorituskyvyssä millisekunneilla on todella väliä!

Juurisyyn vaikutus

Tällä juurisyyllä on mielenkiintoinen vaikutus hajautettuun järjestelmäämme. Yleensä järjestelmät pitävät suuresta läpäisykyvystä, joten erittäin korkea käyttöaste on hyvä asia. Mutta välimuistipalvelimemme käsittelee kahdenlaista liikennettä: (1) suuren läpimenon dataa tietokannasta (2) pieniä kyselyjä API-kerroksesta. Myönnettäköön, että API-kerroksen pyynnöt voivat aiheuttaa tietokannasta tulevaa korkean läpimenon dataa, mutta tässä on avain: sitä tarvitaan vain silloin, kun pyyntöä ei voida täyttää välimuistin avulla. Jos pyyntö on välimuistissa, välimuistipalvelimen pitäisi palauttaa tiedot nopeasti ilman, että tietokannan laskelmia tarvitsee odottaa. Mutta mitä tapahtuu, jos välimuistiin tallennettu pyyntö tulee välimuistiin tallentamattoman pyynnön mikropurkausvastauksen aikana? Mikropurkaus voi aiheuttaa 30 ms:n viiveen muulle saapuvalle liikenteelle, ja siksi välimuistiin tallennettuun pyyntöön voi kohdistua 30 ms:n ylimääräinen viive, joka on täysin tarpeeton!

Vaihe 4: Prototyyppi ja validointi

Kun löysimme uskottavan perussyyn, halusimme validoida tuloksemme. Koska tämä pursuava kaistanleveyden käyttö voi aiheuttaa viivästyksiä välimuistin osumiin, pystyimme eristämään nämä pyynnöt välimuistipalvelimen tietokantaklusteriin tekemistä kyselyistä. Tätä varten perustimme koeympäristön, jossa yhdellä välimuistipalvelinhostilla on kaksi verkkokorttia, joilla kummallakin on oma IP-osoite. Tässä kokoonpanossa kaikki API-kerroksen pyynnöt välimuistipalvelimelle kulkevat yhden rajapinnan kautta ja kaikki välimuistipalvelimen kyselyt tietokantaklusterille toisen rajapinnan kautta. Alla oleva kaavio havainnollistaa tätä:

Tällä kokoonpanolla mittasimme seuraavat viiveet, ja kuten näet, API-kerroksen ja välimuistipalvelimen väliset viiveet ovat itse asiassa sitä, mitä odotamme – terveitä ja alle 1 ms. Tietokantaklusterin kanssa esiintyviä latensseja ei voida välttää ilman parempaa laitteistoa; koska haluamme maksimoida läpäisykyvyn, purskeita tulee aina esiintymään ja näin ollen paketteja jonotetaan rajapinnassa.

Siten eri liikenne ansaitsee eri prioriteetit ja se voi olla ihanteellinen ratkaisu mikropurkautuvan liikenteen käsittelyyn. Muita ratkaisuja ovat laitteiston parantaminen, kuten 10 Gbps:n laitteiston käyttäminen, datan pakkaaminen tai jopa palvelunlaadun käyttäminen.

Pituusviiveiden perimmäisen syyn löytäminen voi olla vaikeaa.

Pituusviiveiden perimmäisen syyn löytäminen voi olla vaikeaa, koska ne ovat ohimeneviä ja ne voivat jäädä suorituskykymittareiden ulkopuolelle. Useimmat suorituskykymittarit, joita keräämme täällä LinkedInissä, ovat yhden sekunnin tarkkuudella ja jotkut yhden minuutin tarkkuudella. Kun kuitenkin otetaan tämä huomioon, 30 ms:n pituiset viiveet jäävät helposti huomaamatta mittauksissa, joiden rakeisuus on jopa 1 000 ms (1 sekunti). Lisäksi pitkät viiveet voivat johtua erilaisista laitteisto- tai ohjelmisto-ongelmista, ja niiden syytä voi olla melko vaikea selvittää monimutkaisessa hajautetussa järjestelmässä. Esimerkkejä syistä voivat olla laitteistoresurssien käyttö, joka liittyy oikeudenmukaisuuteen, riitaisuuteen ja kyllästymiseen, tai datakuvioihin liittyvät ongelmat, kuten monisolmuiset jakaumat tai tehokäyttäjät, jotka aiheuttavat pitkähäntäisiä latensseja työtehtävilleen.

Yhteenvetona kehotamme muistamaan nämä metodologiamme neljä vaihetta tulevia tutkimuksia varten:

  1. Kontrolloidussa ja yksinkertaistetussa ympäristössä.
  2. Saa yksityiskohtaiset päästä-päähän-viiveen mittaukset.
  3. Levitä ja kokeile.
  4. Prototypoi ja validoi.

Oppi oppi

  • Pitkäaikainen latenssi ei ole pelkkää kohinaa! Se voi johtua erilaisista todellisista syistä ja 99. prosenttipisteen pyynnöt voivat vaikuttaa muuhun suureen hajautettuun järjestelmään.
  • Ei kannata väheksyä 99. persentiilin latenssiongelmia tehokäyttäjinä; kun tehokäyttäjät lisääntyvät, myös ongelmat lisääntyvät.
  • Vedon suojaaminen, vaikka se onkin yleisesti ottaen hyvä strategia, jossa järjestelmä lähettää saman pyynnön kahdesti yhden nopean vastauksen toivossa, ei auta, kun pitkähäntäviiveet ovat sovelluksen aiheuttamia. Itse asiassa se vain huonontaa järjestelmää lisäämällä järjestelmään lisää liikennettä, mikä meidän tapauksessamme aiheuttaisi lisää mikropurkauksia. Jos olisimme toteuttaneet tämän strategian ilman perusteellista analyysia, olisimme joutuneet pettymään, koska järjestelmän suorituskyky olisi heikentynyt ja tällaisen ratkaisun toteuttaminen olisi tuhlannut huomattavan paljon vaivaa.
  • Scatter/gather-lähestymistavat voivat helposti aiheuttaa kaistanleveyden käytön mikropurkauksia, jotka aiheuttavat jonotusviiveitä millisekuntien tarkkuudella.
  • Sub-sekunnin rakeisuusmittaukset ovat välttämättömiä.
  • Joskus laitteistoparannukset ovat kustannustehokkain tapa auttaa ongelmien lieventämisessä, mutta siihen asti kehittäjät voivat edelleen tehdä mielenkiintoisia lieventämistoimia, kuten pakata dataa tai olla valikoivia sen suhteen, mitä dataa lähetetään tai käytetään.

Loppujen lopuksi tärkein oppi, jonka opimme, oli menetelmien noudattaminen. Metodologiat antavat suuntaa tutkimuksille, erityisesti silloin, kun asiat muuttuvat sekaviksi tai alkavat tuntua matkalta Keski-Maan halki.

Kiitokset

Haluan kiittää Andrew Carteria hänen työstään ja yhteistyöstään tutkimuksen aikana sekä Steven Callisteria operatiivisesta tuesta ja palautteesta. Kiitokset myös Badri Sridharanille, Haricharan Ramachandralle, Ritesh Maheshwarille ja Zhenyun Zhuangille palautteesta ja ehdotuksista tätä kirjoitusta koskien.