ProHoster > Blogi > Haldamine > SRE: tulemuslikkuse analüüs. Konfigureerimismeetod Go lihtsa veebiserveri abil
SRE: tulemuslikkuse analüüs. Konfigureerimismeetod Go lihtsa veebiserveri abil
Jõudlusanalüüs ja häälestamine on võimas tööriist klientide jõudluse vastavuse kontrollimiseks.
Jõudlusanalüüsi abil saab kontrollida programmi kitsaskohti, rakendades häälestuskatsete testimisel teaduslikku lähenemist. See artikkel määratleb üldise lähenemisviisi jõudluse analüüsile ja häälestamisele, kasutades näiteks Go veebiserverit.
Go on siin eriti hea, kuna sellel on profiilide koostamise tööriistad pprof standardraamatukogus.
strateegia
Koostame oma struktuurianalüüsi jaoks kokkuvõtliku loendi. Püüame kasutada mõningaid andmeid otsuste tegemiseks, selle asemel, et intuitsioonil või oletusel põhinevaid muudatusi teha. Selleks teeme järgmist:
Määrame optimeerimise piirid (nõuded);
Arvutame süsteemi tehingukoormuse;
Teostame testi (loome andmed);
Me jälgime;
Analüüsime – kas kõik nõuded on täidetud?
Seadsime selle teaduslikult paika, püstitame hüpoteesi;
Teeme selle hüpoteesi kontrollimiseks katse.
Lihtne HTTP-serveri arhitektuur
Selle artikli jaoks kasutame Golangis väikest HTTP-serverit. Kogu selle artikli koodi leiate siin.
Analüüsitav rakendus on HTTP-server, mis küsitleb iga päringu kohta Postgresql-i. Lisaks on rakenduste ja süsteemi mõõdikute kogumiseks ja kuvamiseks Prometheus, node_exporter ja Grafana.
Lihtsustamiseks arvestame, et horisontaalseks skaleerimiseks (ja arvutuste lihtsustamiseks) juurutatakse iga teenus ja andmebaas koos:
Eesmärkide määratlemine
Selles etapis otsustame eesmärgi üle. Mida me püüame analüüsida? Kuidas me teame, millal on aeg lõpetada? Selles artiklis kujutame ette, et meil on kliente ja meie teenus töötleb 10 000 päringut sekundis.
В Google SRE raamat Üksikasjalikult käsitletakse valiku- ja modelleerimismeetodeid. Teeme sama ja ehitame mudeleid:
Latentsus: 99% taotlustest peaks olema täidetud vähem kui 60 ms jooksul;
Maksumus: teenus peaks kulutama minimaalse summa raha, mis meie arvates on mõistlikult võimalik. Selleks maksimeerime läbilaskevõimet;
Võimsuse planeerimine: nõuab arusaamist ja dokumenteerimist, kui palju rakenduse eksemplare peab töötama, sealhulgas üldist skaleerimisfunktsiooni, ja mitut eksemplari on vaja esialgse laadimise ja varustamise nõuete täitmiseks. koondamine n+1.
Latentsusaeg võib vajada lisaks analüüsile optimeerimist, kuid läbilaskevõimet tuleb selgelt analüüsida. SRE SLO protsessi kasutamisel tuleb viivitustaotlus kliendilt või ettevõttelt, keda esindab toote omanik. Ja meie teenus täidab selle kohustuse algusest peale ilma igasuguste seadistusteta!
Testikeskkonna seadistamine
Testkeskkonna abil saame oma süsteemile panna mõõdetud koormuse. Analüüsiks genereeritakse andmed veebiteenuse toimivuse kohta.
Tehingukoormus
See keskkond kasutab kiratsema kohandatud HTTP päringu kiiruse loomiseks kuni peatamiseni:
$ 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
Vaatlus
Tehingukoormus rakendatakse käitusajal. Lisaks rakenduse (päringute arv, vastuse latentsus) ja operatsioonisüsteemi (mälu, protsessor, IOPS) mõõdikutele käivitatakse rakenduse profiilide koostamine, et mõista, kus sellel on probleeme ja kuidas kulub protsessori aega.
Profileerimine
Profileerimine on mõõtmise tüüp, mis võimaldab rakenduse töötamise ajal näha, kuhu protsessori aeg kulub. See võimaldab teil täpselt määrata, kuhu ja kui palju protsessori aega kulutatakse:
Neid andmeid saab analüüsi ajal kasutada, et saada ülevaade raisatud protsessori ajast ja tehtavast tarbetust tööst. Go (pprof) saab standardsete tööriistade komplekti kasutades luua profiile ja visualiseerida neid leegigraafikutena. Nende kasutamisest ja seadistamise juhendist räägin hiljem artiklis.
Teostus, vaatlus, analüüs.
Teeme katse. Esineme, vaatleme ja analüüsime seni, kuni oleme sooritusega rahul. Esimeste vaatluste tulemuste saamiseks valime selle rakendamiseks suvaliselt väikese koormuse väärtuse. Igal järgneval etapil suurendame koormust teatud skaleerimisteguriga, mis on valitud teatud variatsioonidega. Iga koormustesti käitamine tehakse kohandatud taotluste arvuga: make load-test LOAD_TEST_RATE=X.
50 päringut sekundis
Pöörake tähelepanu kahele ülemisele graafikule. Vasakpoolses ülanurgas on näha, et meie rakendus töötleb 50 päringut sekundis (ta arvab) ja üleval paremal on iga päringu kestus. Mõlemad parameetrid aitavad meil vaadata ja analüüsida, kas oleme oma tulemuslikkuse piirides või mitte. Punane joon graafikul HTTP päringu latentsus näitab SLO-d 60 ms juures. Joon näitab, et oleme oma maksimaalsest reageerimisajast kõvasti alla jäänud.
Huvitavamad asjad hakkavad juhtuma siis, kui koormus jõuab 500 päringuni sekundis:
Jällegi on üleval vasakpoolsel graafikul näha, et rakendus salvestab tavalist koormust. Kui see nii ei ole, on probleem serveris, kus rakendus töötab. Vastuse latentsusgraafik asub paremas ülanurgas, mis näitab, et 500 päringut sekundis põhjustas vastuse viivituse 25–40 ms. 99. protsentiil sobib ikka kenasti ülal valitud 60ms SLO-sse.
Suurepärane käivitamine! Rakendus näitab, et see töötles 1000 päringut sekundis, kuid SLO rikkus latentsuspiirangut. Seda on näha parempoolse graafiku real p99. Vaatamata asjaolule, et p100 liin on palju kõrgem, on tegelikud viivitused suuremad kui maksimaalne 60 ms. Sukeldume profiilide koostamisse, et teada saada, mida rakendus tegelikult teeb.
Profileerimine
Profileerimiseks määrame koormuse 1000 päringut sekundis, seejärel kasuta pprof andmete kogumiseks, et teada saada, kus rakendus CPU aega kulutab. Seda saab teha HTTP lõpp-punkti aktiveerimisega pprofja seejärel salvestage tulemused koormuse all curl abil:
$ go tool pprof -http=:12345 cpu.1000_reqs_sec_no_optimizations.prof
Graafik näitab, kus ja kui palju rakendus CPU aega kulutab. Alates kirjeldusest alates Brendan Gregg:
X-telg on virna profiili populatsioon, sorteeritud tähestikulises järjekorras (see pole aeg), Y-telg näitab virna sügavust, lugedes nullist [üleval]. Iga ristkülik on virnaraam. Mida laiem on raam, seda sagedamini on see virnades. See, mis on peal, töötab CPU-s ja allpool olevad on alamelemendid. Värvid ei tähenda tavaliselt midagi, vaid valitakse lihtsalt juhuslikult, et raame eristada.
Analüüs – hüpotees
Häälestamiseks keskendume raisatud protsessoriaja leidmisele. Otsime üles suurimad asjatute kulutuste allikad ja eemaldame need. Arvestades, et profiilide koostamine näitab väga täpselt, kus rakendus täpselt oma protsessori aega kulutab, peate võib-olla seda mitu korda tegema, samuti peate muutma rakenduse lähtekoodi, uuesti läbima testid ja veenduma, et jõudlus läheneb eesmärgile.
Järgides Brendan Greggi soovitusi, loeme diagrammi ülalt alla. Igal real kuvatakse virnaraam (funktsiooni kutse). Esimene rida on programmi sisenemispunkt, kõigi teiste kõnede vanem (teisisõnu on see kõigi teiste kõnede pinus). Järgmine rida on juba erinev:
Kui hõljutate kursorit graafikul funktsiooni nime kohal, kuvatakse kogu aeg, mil see silumise ajal virnas oli. Funktsioon HTTPServe oli seal 65% ajast, muud käitusaegsed funktsioonid runtime.mcall, mstart и gc, võttis ülejäänud aja. Lõbus fakt: 5% kogu ajast kulub DNS-päringutele:
Aadressid, mida programm otsib, kuuluvad Postgresqli. Kliki FindByAge:
Huvitaval kombel näitab programm, et põhimõtteliselt on kolm peamist viivitusi lisavat allikat: ühenduste avamine ja sulgemine, andmete küsimine ja andmebaasiga ühenduse loomine. Graafik näitab, et DNS-i päringud, ühenduste avamine ja sulgemine võtavad umbes 13% kogu täitmisajast.
Hüpotees: Ühenduste taaskasutamine puuli abil peaks vähendama ühe HTTP-päringu aega, võimaldades suuremat läbilaskevõimet ja väiksemat latentsust.
Rakenduse seadistamine – katse
Värskendame lähtekoodi, proovime iga päringu puhul eemaldada ühenduse Postgresqliga. Esimene võimalus on kasutada ühendusbassein rakenduse tasemel. Selles katses me paneme selle paika ühenduste ühendamine SQL-draiveri abil:
Koormuse kahekordistamine näitab sama, ülemine vasak graafik näitab, et rakendus suudab töödelda 2000 päringut sekundis, p100 on alla 60 ms, p99 rahuldab SLO.
Siin saab rakendus töödelda 3000 päringut p99 latentsusajaga alla 60 ms. SLO-d ei rikuta ja kulud aktsepteeritakse järgmiselt:
10000 3000 päringut sekundis / 4 päringu kohta serveri kohta = 1 serverit + XNUMX (autor on ümardanud, u. tõlkija)
Proovime teist analüüsivooru.
Analüüs – hüpotees
Kogume ja kuvame rakenduse silumise tulemusi kiirusega 3000 päringut sekundis:
Siiski kulub 6% ajast ühenduste loomisele. Puuli seadistamine on parandanud jõudlust, kuid näete siiski, et rakendus jätkab andmebaasiga uute ühenduste loomist.
Hüpotees: Ühendused, hoolimata basseini olemasolust, katkestatakse ja puhastatakse, seega peab rakendus need lähtestama. Ootel olevate ühenduste arvu määramine kogumi suurusele peaks aitama vähendada latentsust, vähendades aega, mis rakendusel ühenduse loomisele kulub.
Rakenduse seadistamine – katse
Proovin installida MaxIdleConns võrdne basseini suurusega (kirjeldatud ka siin):
Leegi graafikut kontrollides on näha, et ühendust pole enam märgata! Kontrollime üksikasjalikumalt pg(*conn).query — me ei märka siin ka ühenduse tekkimist.
Järeldus
Jõudlusanalüüs on ülioluline, et mõista, et klientide ootused ja mittefunktsionaalsed nõuded on täidetud. Analüüs, milles võrreldakse tähelepanekuid klientide ootustega, võib aidata kindlaks teha, mis on vastuvõetav ja mis mitte. Go pakub standardteegi sisseehitatud võimsaid tööriistu, mis muudavad analüüsi lihtsaks ja juurdepääsetavaks.