SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

A teljesítményelemzés és hangolás hatékony eszköz a teljesítmény megfelelőségének ellenőrzésére az ügyfelek számára.

A teljesítményelemzés segítségével ellenőrizhető a program szűk keresztmetszete a hangolási kísérletek tesztelésének tudományos megközelítésével. Ez a cikk a teljesítményelemzés és hangolás általános megközelítését írja le, példaként egy Go webszerver használatával.

A Go itt különösen jó, mert profilkészítő eszközökkel rendelkezik pprof a standard könyvtárban.

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

stratégia

Készítsünk összefoglaló listát szerkezeti elemzésünkhöz. Megpróbálunk bizonyos adatokat felhasználni a döntések meghozatalához, ahelyett, hogy intuíción vagy találgatásokon alapuló változtatásokat hajtanánk végre. Ehhez a következőket fogjuk tenni:

  • Meghatározzuk az optimalizációs határokat (követelményeket);
  • Kiszámoljuk a rendszer tranzakciós terhelését;
  • Elvégezzük a tesztet (adatokat hozunk létre);
  • Megfigyeljük;
  • Elemezzük – minden követelmény teljesül?
  • Tudományosan állítjuk fel, hipotézist állítunk fel;
  • Kísérletet végzünk ennek a hipotézisnek a tesztelésére.

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Egyszerű HTTP szerver architektúra

Ebben a cikkben egy kis HTTP-kiszolgálót fogunk használni Golangban. A cikkben szereplő összes kód megtalálható itt.

Az elemzett alkalmazás egy HTTP-kiszolgáló, amely minden kérés esetén lekérdezi a Postgresql-t. Ezenkívül a Prometheus, a node_exporter és a Grafana az alkalmazás- és rendszermutatók összegyűjtésére és megjelenítésére szolgál.

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Az egyszerűsítés érdekében figyelembe vesszük, hogy a vízszintes méretezéshez (és a számítások egyszerűsítéséhez) minden szolgáltatás és adatbázis együtt kerül telepítésre:

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Célok meghatározása

Ebben a lépésben döntünk a célról. Mit próbálunk elemezni? Honnan tudjuk, hogy mikor jön el a vég? Ebben a cikkben azt képzeljük el, hogy vannak ügyfeleink, és szolgáltatásunk másodpercenként 10 000 kérelmet dolgoz fel.

В Google SRE Book A kiválasztási és modellezési módszereket részletesen tárgyaljuk. Tegyük meg ugyanezt, és készítsünk modelleket:

  • Késés: a kérelmek 99%-át 60 ms-nál rövidebb idő alatt kell teljesíteni;
  • Költség: A szolgáltatásnak az általunk ésszerűen lehetségesnek tartott minimális összeget kell felemésztenie. Ehhez maximalizáljuk az áteresztőképességet;
  • Kapacitástervezés: Meg kell érteni és dokumentálni kell, hogy az alkalmazás hány példányát kell futtatni, beleértve az általános méretezési funkcionalitást, és hány példányra lesz szükség a kezdeti betöltési és üzembe helyezési követelmények teljesítéséhez. redundancia n+1.

A késleltetés az elemzés mellett optimalizálást is igényelhet, de az átviteli sebességet egyértelműen elemezni kell. Az SRE SLO folyamat használatakor a késleltetési kérelem az ügyféltől vagy a vállalkozástól érkezik, amelyet a termék tulajdonosa képvisel. Ennek a kötelezettségünknek pedig szolgáltatásunk kezdettől fogva minden beállítás nélkül eleget tesz!

Tesztkörnyezet beállítása

Egy tesztkörnyezet segítségével mért terhelést tudunk majd helyezni rendszerünkre. Az elemzéshez a webszolgáltatás teljesítményére vonatkozó adatok generálódnak.

Tranzakciós terhelés

Ez a környezet használ Vegetál egyéni HTTP kérési sebesség létrehozásához a leállításig:

$ make load-test LOAD_TEST_RATE=50
echo "POST http://localhost:8080" | vegeta attack -body tests/fixtures/age_no_match.json -rate=50 -duration=0 | tee results.bin | vegeta report

őrzés

A tranzakciós terhelés futásidőben kerül alkalmazásra. Az alkalmazás (kérelmek száma, válasz késleltetése) és operációs rendszer (memória, CPU, IOPS) mérőszámain kívül az alkalmazás profilalkotása is lefut, hogy megértse, hol vannak problémái, és hogyan fogyasztja el a CPU-időt.

Profilalkotás

A profilalkotás egy olyan típusú mérés, amely lehetővé teszi annak megtekintését, hogy hová telik a CPU-idő, amikor egy alkalmazás fut. Lehetővé teszi, hogy pontosan meghatározza, hol és mennyi processzoridőt tölt:

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Ezek az adatok felhasználhatók az elemzés során, hogy betekintést nyerjenek az elpazarolt CPU-időbe és a feleslegesen elvégzett munkába. A Go (pprof) képes profilokat generálni és lánggrafikonként megjeleníteni szabványos eszközkészlettel. Használatukról és beállítási útmutatójukról a cikk későbbi részében fogok beszélni.

Végrehajtás, megfigyelés, elemzés.

Végezzünk egy kísérletet. Addig fogunk előadni, megfigyelni és elemezni, amíg elégedettek nem leszünk a teljesítménnyel. Válasszunk egy tetszőlegesen alacsony terhelési értéket annak alkalmazásához, hogy megkapjuk az első megfigyelések eredményeit. Minden következő lépésben növeljük a terhelést egy bizonyos skálázási tényezővel, amelyet némi változtatással választunk. Minden egyes terhelési tesztelési futtatás a kérelmek számának módosításával történik: make load-test LOAD_TEST_RATE=X.

50 kérés másodpercenként

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Ügyeljen a felső két grafikonra. A bal felső sarokban látható, hogy az alkalmazásunk másodpercenként 50 kérést dolgoz fel (gondolja), a jobb felső pedig az egyes kérések időtartamát mutatja. Mindkét paraméter segít annak megvizsgálásában és elemzésében, hogy a teljesítményhatárainkon belül vagyunk-e vagy sem. Piros vonal a grafikonon HTTP-kérés késleltetése SLO-t mutat 60 ms-nál. A vonal azt mutatja, hogy jóval a maximális válaszidő alatt vagyunk.

Nézzük a költségek oldalát:

10000 50 kérés másodpercenként / 200 kérés szerverenként = 1 szerver + XNUMX

Ezen a számon még javíthatunk.

500 kérés másodpercenként

Érdekesebb dolgok kezdenek történni, amikor a terhelés eléri az 500 kérést másodpercenként:

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Ismét a bal felső grafikonon látható, hogy az alkalmazás normál terhelést rögzít. Ha nem ez a helyzet, akkor probléma van azon a szerveren, amelyen az alkalmazás fut. A válasz késleltetési grafikonja a jobb felső sarokban található, és azt mutatja, hogy másodpercenként 500 kérés 25-40 ms válaszkésleltetést eredményezett. A 99. percentilis még mindig szépen belefér a fent választott 60 ms-os SLO-ba.

Költség szempontjából:

10000 500 kérés másodpercenként / 20 kérés szerverenként = 1 szerver + XNUMX

Még minden javítható.

1000 kérés másodpercenként

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Nagyszerű start! Az alkalmazás azt mutatja, hogy másodpercenként 1000 kérést dolgozott fel, de az SLO megsértette a késleltetési korlátot. Ez a jobb felső grafikon p99-es sorban látható. Annak ellenére, hogy a p100 vonal jóval magasabb, a tényleges késések nagyobbak, mint a maximum 60 ms. Merüljünk el a profilalkotásban, hogy megtudjuk, mit is csinál az alkalmazás valójában.

Profilalkotás

A profilalkotáshoz a terhelést 1000 kérés/másodperc értékre állítjuk, majd használjuk pprof adatok rögzítésére, hogy megtudja, hol tölti a CPU-időt az alkalmazás. Ezt a HTTP-végpont aktiválásával teheti meg pprof, majd terhelés alatt mentse el az eredményeket a curl használatával:

$ curl http://localhost:8080/debug/pprof/profile?seconds=29 > cpu.1000_reqs_sec_no_optimizations.prof

Az eredmények a következőképpen jeleníthetők meg:

$ go tool pprof -http=:12345 cpu.1000_reqs_sec_no_optimizations.prof

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

A grafikonon látható, hogy az alkalmazás hol és mennyit tölt CPU-idővel. A leírásból származó Brendan Gregg:

Az X tengely a veremprofil populáció, ábécé szerint rendezve (ez nem idő), az Y tengely a verem mélységét mutatja, nullától számolva [felül]. Minden téglalap egy halom keret. Minél szélesebb a keret, annál gyakrabban van jelen a kötegekben. Ami felül van, az a CPU-n fut, az alatta lévők pedig a gyermekelemek. A színek általában nem jelentenek semmit, egyszerűen véletlenszerűen választják ki a kereteket.

Elemzés – hipotézis

A hangolásnál az elpazarolt CPU-idő megtalálására összpontosítunk. Megkeressük a haszontalan kiadások legnagyobb forrásait, és eltávolítjuk őket. Nos, mivel a profilozás nagyon pontosan megmutatja, hogy az alkalmazás pontosan hol tölti a processzor idejét, előfordulhat, hogy többször is meg kell tennie, és meg kell változtatnia az alkalmazás forráskódját, újra kell futtatnia a teszteket, és látnia kell, hogy a teljesítmény megközelíti a célt.

Brendan Gregg ajánlásait követve felülről lefelé olvassuk el a diagramot. Minden sor egy verem keretet jelenít meg (függvényhívás). Az első sor a program belépési pontja, az összes többi hívás szülője (az összes többi hívásnak a veremében lesz). A következő sor már más:

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Ha a kurzort egy függvény neve fölé viszi a grafikonon, akkor megjelenik a hibakeresés során a veremben töltött teljes időtartam. A HTTPServe funkció az esetek 65%-ában ott volt, más futásidejű funkciók runtime.mcall, mstart и gc, a fennmaradó időt igénybe vette. Érdekes tény: a teljes idő 5%-át DNS-lekérdezésekre fordítják:

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

A program által keresett címek a Postgresql-hez tartoznak. Kattintson FindByAge:

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Érdekes módon a program megmutatja, hogy elvileg három fő forrás van, amely késleltetést okoz: a kapcsolatok nyitása és lezárása, az adatok lekérése és az adatbázishoz való csatlakozás. A grafikon azt mutatja, hogy a DNS-kérések, a kapcsolatok megnyitása és lezárása a teljes végrehajtási idő körülbelül 13%-át teszik ki.

Hipotézis: A kapcsolatok pooling használatával történő újrafelhasználása csökkenti az egyetlen HTTP-kérés idejét, ami nagyobb átviteli sebességet és alacsonyabb késleltetést tesz lehetővé.

Az alkalmazás beállítása - kísérlet

Frissítjük a forráskódot, megpróbáljuk eltávolítani a kapcsolatot a Postgresql-lel minden kérésnél. Az első lehetőség a használat kapcsolati medence az alkalmazás szintjén. Ebben a kísérletben mi állítsuk fel kapcsolat pooling sql illesztőprogram használatával:

db, err := sql.Open("postgres", dbConnectionString)
db.SetMaxOpenConns(8)

if err != nil {
   return nil, err
}

Végrehajtás, megfigyelés, elemzés

A teszt másodpercenkénti 1000 kéréssel történő újraindítása után egyértelmű, hogy a p99 késleltetési szintjei 60 ms-os SLO-val normalizálódtak!

mennyibe kerül?

10000 1000 kérés másodpercenként / 10 kérés szerverenként = 1 szerver + XNUMX

Csináljuk még jobban!

2000 kérés másodpercenként

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

A terhelés megkétszerezése ugyanezt mutatja, a bal felső grafikon azt mutatja, hogy az alkalmazás másodpercenként 2000 kérést tud feldolgozni, a p100 kisebb, mint 60 ms, a p99 kielégíti az SLO-t.

Költség szempontjából:

10000 2000 kérés másodpercenként / 5 kérés szerverenként = 1 szerver + XNUMX

3000 kérés másodpercenként

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Itt az alkalmazás 3000 kérést tud feldolgozni 99 ms-nál rövidebb p60 késleltetéssel. Az SLO-t nem sértik meg, és a költségeket az alábbiak szerint fogadjuk el:

10000 3000 kérés másodpercenként / 4 1 kérés szerverenként = XNUMX szerver + XNUMX (a szerző felkerekedett, kb. fordító)

Próbáljunk meg egy újabb elemzési kört.

Elemzés – hipotézis

Az alkalmazás hibakeresésének eredményeit másodpercenként 3000 kéréssel gyűjtjük és jelenítjük meg:

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Még mindig az idő 6%-át a kapcsolatok kialakítására fordítják. A készlet beállítása javította a teljesítményt, de továbbra is látható, hogy az alkalmazás továbbra is dolgozik az adatbázishoz fűződő új kapcsolatok létrehozásán.

Hipotézis: A kapcsolatok a medence jelenléte ellenére továbbra is megszakadnak és megtisztulnak, ezért az alkalmazásnak vissza kell állítania őket. A függőben lévő kapcsolatok számának a készlet méretére való beállítása segíti a késleltetést azáltal, hogy minimalizálja azt az időt, amelyet az alkalmazás a kapcsolat létrehozásával tölt..

Az alkalmazás beállítása - kísérlet

Telepíteni próbál MaxIdleConns megegyezik a medence méretével (leírva is itt):

db, err := sql.Open("postgres", dbConnectionString)
db.SetMaxOpenConns(8)
db.SetMaxIdleConns(8)
if err != nil {
   return nil, err
}

Végrehajtás, megfigyelés, elemzés

3000 kérés másodpercenként

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

A p99 kevesebb mint 60 ms, lényegesen kevesebb p100-al!

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

A lánggrafikon ellenőrzése azt mutatja, hogy a kapcsolat már nem észrevehető! Nézzük részletesebben pg(*conn).query – itt sem vesszük észre a kapcsolat létrejöttét.

SRE: Teljesítményelemzés. Konfigurációs módszer egy egyszerű webszerver használatával a Go-ban

Következtetés

A teljesítményelemzés kritikus fontosságú annak megértéséhez, hogy az ügyfelek elvárásai és a nem funkcionális követelmények teljesülnek. A megfigyelések és a vásárlói elvárások összehasonlításával végzett elemzés segíthet meghatározni, hogy mi elfogadható és mi nem. A Go a szabványos könyvtárba beépített hatékony eszközöket kínál, amelyek egyszerűvé és hozzáférhetővé teszik az elemzést.

Forrás: will.com

Hozzászólás