SRE: našumo analizė. Konfigūravimo metodas naudojant paprastą žiniatinklio serverį Go
Našumo analizė ir derinimas yra galingas įrankis, leidžiantis patikrinti, ar klientai laikosi veiklos rezultatų.
Našumo analizė gali būti naudojama norint patikrinti, ar programoje nėra kliūčių, taikant mokslinį požiūrį į derinimo eksperimentų testavimą. Šiame straipsnyje apibrėžiamas bendras požiūris į našumo analizę ir derinimą, kaip pavyzdį naudojant „Go“ žiniatinklio serverį.
„Go“ čia ypač geras, nes turi profiliavimo įrankius pprof standartinėje bibliotekoje.
strategija
Sukurkime struktūrinės analizės suvestinį sąrašą. Bandysime panaudoti kai kuriuos duomenis, kad priimtume sprendimus, užuot darę pakeitimus remdamiesi intuicija ar spėlionėmis. Norėdami tai padaryti, atliksime šiuos veiksmus:
Nustatome optimizavimo ribas (reikalavimus);
Apskaičiuojame transakcijų apkrovą sistemai;
Atliekame testą (sukuriame duomenis);
Stebime;
Analizuojame – ar tenkinami visi reikalavimai?
Mes jį nustatome moksliškai, keliame hipotezę;
Šiai hipotezei patikrinti atliekame eksperimentą.
Paprasta HTTP serverio architektūra
Šiam straipsniui naudosime nedidelį HTTP serverį Golange. Visą kodą iš šio straipsnio galite rasti čia.
Analizuojama programa yra HTTP serveris, kuris kiekvieną užklausą apklausia Postgresql. Be to, yra „Prometheus“, „node_exporter“ ir „Grafana“, skirtos programų ir sistemos metrikai rinkti ir rodyti.
Siekiant supaprastinti, manome, kad horizontaliam mastelio keitimui (ir supaprastinant skaičiavimus) kiekviena paslauga ir duomenų bazė yra diegiamos kartu:
Tikslų apibrėžimas
Šiame žingsnyje mes apsisprendžiame dėl tikslo. Ką mes bandome analizuoti? Kaip mes žinome, kada laikas baigti? Šiame straipsnyje įsivaizduosime, kad turime klientų ir mūsų paslauga apdoros 10 000 užklausų per sekundę.
В Google SRE knyga Išsamiai aptariami atrankos ir modeliavimo būdai. Padarykime tą patį ir kurkime modelius:
Vėlavimas: 99 % užklausų turi būti įvykdytos greičiau nei per 60 ms;
Kaina: paslauga turėtų sunaudoti mažiausią pinigų sumą, kuri, mūsų manymu, yra pagrįstai įmanoma. Norėdami tai padaryti, maksimaliai padidiname pralaidumą;
Pajėgumų planavimas: reikia suprasti ir dokumentuoti, kiek programos egzempliorių reikės paleisti, įskaitant bendrą mastelio keitimo funkciją ir kiek egzempliorių reikės, kad būtų patenkinti pradiniai įkėlimo ir aprūpinimo reikalavimai. perteklius n+1.
Be analizės gali reikėti optimizuoti delsą, tačiau akivaizdu, kad reikia analizuoti pralaidumą. Naudojant SRE SLO procesą, vėlavimo užklausą pateikia klientas arba įmonė, atstovaujama produkto savininko. Ir mūsų paslauga šį įsipareigojimą vykdys nuo pat pradžių be jokių nustatymų!
Bandymo aplinkos nustatymas
Testinės aplinkos pagalba galėsime įdėti išmatuotą apkrovą mūsų sistemai. Analizei bus generuojami duomenys apie žiniatinklio paslaugos našumą.
Sandorio apkrova
Ši aplinka naudoja vegetuoti Norėdami sukurti pasirinktinį HTTP užklausos greitį iki sustabdymo:
$ 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
Stebėjimas
Operacijos apkrova bus taikoma vykdymo metu. Be programos (užklausų skaičiaus, atsakymo delsos) ir operacinės sistemos (atminties, procesoriaus, IOPS) metrikos, bus vykdomas programos profiliavimas, siekiant suprasti, kur ji turi problemų ir kaip eikvojamas procesoriaus laikas.
Profiliavimas
Profiliavimas yra matavimo tipas, leidžiantis matyti, kur eina procesoriaus laikas, kai programa veikia. Tai leidžia tiksliai nustatyti, kur ir kiek procesoriaus laiko praleidžiama:
Šie duomenys gali būti naudojami atliekant analizę, kad būtų galima suprasti sugaištą procesoriaus laiką ir atliekamą nereikalingą darbą. Go (pprof) gali generuoti profilius ir vizualizuoti juos kaip liepsnos grafikus, naudodama standartinį įrankių rinkinį. Apie jų naudojimą ir sąrankos vadovą kalbėsiu vėliau šiame straipsnyje.
Vykdymas, stebėjimas, analizė.
Padarykime eksperimentą. Atliksime, stebėsime ir analizuosime tol, kol būsime patenkinti pasirodymu. Pasirinkime savavališkai mažą apkrovos reikšmę, kurią taikysime, kad gautume pirmųjų stebėjimų rezultatus. Kiekviename paskesniame žingsnyje mes padidinsime apkrovą tam tikru mastelio koeficientu, pasirinktu su tam tikra variacija. Kiekvienas apkrovos bandymo paleidimas atliekamas su pakoreguotu užklausų skaičiumi: make load-test LOAD_TEST_RATE=X.
50 užklausų per sekundę
Atkreipkite dėmesį į dvi viršutines diagramas. Viršuje kairėje rodoma, kad mūsų programa apdoroja 50 užklausų per sekundę (ji mano), o viršuje dešinėje rodoma kiekvienos užklausos trukmė. Abu parametrai padeda mums pažvelgti ir analizuoti, ar esame savo veiklos ribose, ar ne. Raudona linija diagramoje HTTP užklausos delsa rodo SLO esant 60 ms. Linija rodo, kad esame gerokai trumpesni nei maksimalus atsako laikas.
Pažvelkime į išlaidų pusę:
10000 50 užklausų per sekundę / 200 užklausų vienam serveriui = 1 serverių + XNUMX
Dar galime pagerinti šį skaičių.
500 užklausų per sekundę
Įdomesni dalykai pradeda vykti, kai apkrova pasiekia 500 užklausų per sekundę:
Vėlgi, viršutiniame kairiajame schemoje matote, kad programa įrašo įprastą apkrovą. Jei taip nėra, serveryje, kuriame veikia programa, kilo problema. Atsakymo delsos grafikas yra viršuje dešinėje, rodantis, kad 500 užklausų per sekundę lėmė 25–40 ms atsakymo delsą. 99-asis procentilis vis dar puikiai tinka aukščiau pasirinktam 60 ms SLO.
Kalbant apie išlaidas:
10000 500 užklausų per sekundę / 20 užklausų vienam serveriui = 1 serverių + XNUMX
Viską dar galima patobulinti.
1000 užklausų per sekundę
Puikus startas! Programa rodo, kad ji apdorojo 1000 užklausų per sekundę, tačiau SLO pažeidė delsos limitą. Tai galima pamatyti p99 eilutėje viršutiniame dešiniajame grafike. Nepaisant to, kad p100 linija yra daug aukštesnė, faktiniai vėlavimai yra didesni nei maksimalus 60 ms. Pasinerkime į profiliavimą, kad sužinotume, ką iš tikrųjų daro programa.
Profiliavimas
Profiliavimui nustatome 1000 užklausų per sekundę apkrovą, tada naudokite pprof fiksuoti duomenis ir sužinoti, kur programa praleidžia procesoriaus laiką. Tai galima padaryti suaktyvinus HTTP galinį tašką pprof, o tada, kai apkrova, išsaugokite rezultatus naudodami curl:
$ go tool pprof -http=:12345 cpu.1000_reqs_sec_no_optimizations.prof
Diagrama rodo, kur ir kiek programa praleidžia CPU laiko. Iš aprašymo iš Brendanas Gregas:
X ašis yra krūvos profilio visuma, surūšiuota abėcėlės tvarka (tai ne laikas), Y ašis rodo krūvos gylį, skaičiuojant nuo nulio [viršuje]. Kiekvienas stačiakampis yra krūvos rėmas. Kuo platesnis rėmas, tuo dažniau jis yra rietuvėse. Tai, kas yra viršuje, veikia CPU, o tai, kas yra žemiau, yra antriniai elementai. Spalvos dažniausiai nieko nereiškia, o tiesiog pasirenkamos atsitiktinai, kad atskirtų rėmus.
Analizė – hipotezė
Derindami sutelksime dėmesį į tai, kaip rasti švaistomą procesoriaus laiką. Ieškosime didžiausių nenaudingų išlaidų šaltinių ir juos pašalinsime. Na, o atsižvelgiant į tai, kad profiliavimas labai tiksliai atskleidžia, kur programa praleidžia savo procesoriaus laiką, gali tekti tai padaryti kelis kartus, taip pat reikės pakeisti programos šaltinio kodą, iš naujo atlikti testus ir įsitikinti, kad našumas artėja prie tikslo.
Vadovaudamiesi Brendano Greggo rekomendacijomis, diagramą skaitysime iš viršaus į apačią. Kiekvienoje eilutėje rodomas krūvos rėmelis (funkcijos iškvietimas). Pirmoji eilutė yra įėjimo į programą taškas, visų kitų skambučių pirminė eilutė (kitaip tariant, visi kiti skambučiai turės jį savo krūvoje). Kita eilutė jau kitokia:
Jei užvedate pelės žymeklį virš funkcijos pavadinimo grafike, bus rodomas bendras laikas, kai ji buvo krūvoje derinimo metu. HTTPServe funkcija buvo 65% laiko, kitos vykdymo funkcijos runtime.mcall, mstart и gc, užėmė likusį laiką. Įdomus faktas: 5% viso laiko praleidžiama DNS užklausoms:
Adresai, kurių ieško programa, priklauso Postgresql. Spustelėkite FindByAge:
Įdomu tai, kad programa rodo, kad iš principo yra trys pagrindiniai šaltiniai, kurie prideda vėlavimo: jungčių atidarymas ir uždarymas, duomenų užklausa ir prisijungimas prie duomenų bazės. Diagrama rodo, kad DNS užklausos, jungčių atidarymas ir uždarymas užima apie 13% viso vykdymo laiko.
Hipotezė: Pakartotinis jungčių naudojimas naudojant telkimą turėtų sutrumpinti vienos HTTP užklausos laiką, kad būtų padidintas pralaidumas ir mažesnė delsa.
Programos nustatymas – eksperimentas
Atnaujiname šaltinio kodą, bandome pašalinti ryšį su Postgresql kiekvienai užklausai. Pirmasis variantas yra naudoti prijungimo baseinas taikymo lygiu. Šiame eksperimente mes nustatykime ryšio telkimas naudojant sql tvarkyklę for go:
Iš naujo paleidus testą su 1000 užklausų per sekundę, aišku, kad p99 delsos lygiai grįžo į normalią 60 ms SLO!
Kokia kaina?
10000 1000 užklausų per sekundę / 10 užklausų vienam serveriui = 1 serverių + XNUMX
Padarykime tai dar geriau!
2000 užklausų per sekundę
Dvigubai apkrova rodo tą patį, viršutinis kairysis grafikas rodo, kad programa sugeba apdoroti 2000 užklausų per sekundę, p100 yra mažesnis nei 60 ms, p99 tenkina SLO.
Kalbant apie išlaidas:
10000 2000 užklausų per sekundę / 5 užklausų vienam serveriui = 1 serverių + XNUMX
3000 užklausų per sekundę
Čia programa gali apdoroti 3000 užklausų, kurių p99 delsa yra mažesnė nei 60 ms. SLO nepažeidžiamas, o kaina priimama taip:
10000 3000 užklausų per sekundę / 4 1 užklausų vienam serveriui = XNUMX serveriai + XNUMX (autorius suapvalino, apytiksliai vertėjas)
Pabandykime atlikti kitą analizės etapą.
Analizė – hipotezė
Mes renkame ir rodome programos derinimo rezultatus 3000 užklausų per sekundę:
Vis dar 6% laiko skiriama ryšiams užmegzti. Nustačius telkinį pagerėjo našumas, bet vis tiek matote, kad programa ir toliau kuria naujus ryšius su duomenų baze.
Hipotezė: Nepaisant to, kad yra baseinas, ryšiai vis dar nutraukiami ir išvalomi, todėl programai reikia juos iš naujo nustatyti. Laukiančių jungčių skaičiaus nustatymas pagal telkinio dydį turėtų padėti sumažinti delsą, nes sumažinamas laikas, kurį programa praleidžia kurdama ryšį.
Programos nustatymas – eksperimentas
Bandoma įdiegti MaxIdleConns lygus baseino dydžiui (taip pat aprašyta čia):
p99 yra mažesnis nei 60 ms ir žymiai mažesnis p100!
Patikrinus liepsnos grafiką matyti, kad ryšio nebepastebi! Patikrinkime išsamiau pg(*conn).query - mes taip pat nepastebime čia užmezgamo ryšio.
išvada
Veiklos analizė yra labai svarbi norint suprasti, kad klientų lūkesčiai ir nefunkciniai reikalavimai tenkinami. Analizė, lygindama pastebėjimus su klientų lūkesčiais, gali padėti nustatyti, kas yra priimtina, o kas ne. „Go“ teikia galingus įrankius, integruotus į standartinę biblioteką, kurie padaro analizę paprastą ir prieinamą.