SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Suorituskyvyn analysointi ja viritys on tehokas työkalu asiakkaiden suorituskyvyn vaatimustenmukaisuuden tarkistamiseen.

Suorituskykyanalyysin avulla voidaan tarkistaa ohjelman pullonkauloja soveltamalla tieteellistä lähestymistapaa virityskokeilujen testaamiseen. Tässä artikkelissa määritellään yleinen lähestymistapa suorituskyvyn analysointiin ja viritykseen käyttämällä esimerkkinä Go-verkkopalvelinta.

Go on erityisen hyvä täällä, koska siinä on profilointityökaluja pprof vakiokirjastossa.

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

strategia

Luodaan yhteenvetolista rakenneanalyysiämme varten. Yritämme käyttää joitakin tietoja päätösten tekemiseen sen sijaan, että tekisimme muutoksia intuitioon tai arvaukseen perustuen. Tätä varten teemme näin:

  • Määritämme optimoinnin rajat (vaatimukset);
  • Laskemme järjestelmän tapahtumakuorman;
  • Suoritamme testin (luomme dataa);
  • Me tarkkailemme;
  • Analysoimme - täyttyvätkö kaikki vaatimukset?
  • Asetamme sen tieteellisesti, teemme hypoteesin;
  • Suoritamme kokeen tämän hypoteesin testaamiseksi.

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Yksinkertainen HTTP-palvelinarkkitehtuuri

Tässä artikkelissa käytämme pientä HTTP-palvelinta Golangissa. Kaikki tämän artikkelin koodit löytyvät täällä.

Analysoitava sovellus on HTTP-palvelin, joka kysyy Postgresql:stä jokaisesta pyynnöstä. Lisäksi on Prometheus, node_exporter ja Grafana sovellusten ja järjestelmien mittareiden keräämiseen ja näyttämiseen.

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Yksinkertaistamisen vuoksi katsomme, että vaakasuuntaista skaalausta varten (ja laskelmien yksinkertaistamiseksi) jokainen palvelu ja tietokanta otetaan käyttöön yhdessä:

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Tavoitteiden määrittely

Tässä vaiheessa päätämme tavoitteen. Mitä yritämme analysoida? Mistä tiedämme, milloin on aika lopettaa? Tässä artikkelissa kuvittelemme, että meillä on asiakkaita ja että palvelumme käsittelee 10 000 pyyntöä sekunnissa.

В Google SRE Book Valinta- ja mallintamistapoja käsitellään yksityiskohtaisesti. Tehdään samoin ja rakennetaan malleja:

  • Latenssi: 99 % pyynnöistä tulee suorittaa alle 60 ms:ssa;
  • Kustannukset: Palvelun tulee kuluttaa mahdollisimman vähän rahaa, jonka pidämme kohtuullisena. Tätä varten maksimoimme suorituskyvyn;
  • Kapasiteetin suunnittelu: Edellyttää ymmärrystä ja dokumentointia, kuinka monta sovelluksen esiintymää on suoritettava, mukaan lukien yleiset skaalaustoiminnot ja kuinka monta esiintymää tarvitaan alkulataus- ja provisiointivaatimusten täyttämiseen. redundanssi n+1.

Latenssi saattaa vaatia optimointia analyysin lisäksi, mutta suorituskyky on selvästi analysoitava. SRE SLO -prosessia käytettäessä viivepyyntö tulee asiakkaalta tai yritykseltä, jota edustaa tuotteen omistaja. Ja palvelumme täyttää tämän velvoitteen alusta alkaen ilman asetuksia!

Testiympäristön luominen

Testiympäristön avulla voimme asettaa mitatun kuormituksen järjestelmäämme. Analysointia varten luodaan dataa verkkopalvelun toimivuudesta.

Tapahtuman kuormitus

Tämä ympäristö käyttää elää tyhjää elämää luodaksesi mukautetun HTTP-pyyntönopeuden pysäyttämiseen asti:

$ 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

katselu

Tapahtumakuormitus otetaan käyttöön suoritusaikana. Sovelluksen (pyyntöjen määrä, vastausviive) ja käyttöjärjestelmän (muisti, prosessori, IOPS) mittareiden lisäksi ajetaan sovelluksen profilointi, jotta voidaan selvittää, missä sillä on ongelmia ja kuinka suorittimen aikaa kuluu.

Profilointi

Profilointi on eräänlainen mittaus, jonka avulla voit nähdä, mihin CPU-aika kuluu, kun sovellus on käynnissä. Sen avulla voit määrittää tarkalleen missä ja kuinka paljon prosessoriaikaa käytetään:

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Näitä tietoja voidaan käyttää analyysin aikana saadakseen käsityksen hukkaan käytetystä prosessoriajasta ja tarpeettomasta työstä. Go (pprof) voi luoda profiileja ja visualisoida ne liekkikaavioina käyttämällä vakiotyökaluja. Kerron niiden käytöstä ja asennusoppaasta myöhemmin artikkelissa.

Toteutus, tarkkailu, analyysi.

Tehdään kokeilu. Suoritamme, tarkkailemme ja analysoimme, kunnes olemme tyytyväisiä suoritukseen. Valitaan mielivaltaisen pieni kuormitusarvo soveltamaan sitä ensimmäisten havaintojen tulosten saamiseksi. Jokaisessa myöhemmässä vaiheessa lisäämme kuormaa tietyllä skaalauskertoimella, joka valitaan tietyllä vaihtelulla. Jokainen kuormitustestaus suoritetaan siten, että pyyntöjen määrä on säädetty: make load-test LOAD_TEST_RATE=X.

50 pyyntöä sekunnissa

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Kiinnitä huomiota kahteen ylimpään kaavioon. Vasemmassa yläkulmassa näkyy, että sovelluksemme käsittelee 50 pyyntöä sekunnissa (se ajattelee) ja oikeassa yläkulmassa kunkin pyynnön kesto. Molemmat parametrit auttavat meitä tarkastelemaan ja analysoimaan, olemmeko suorituskyvyn rajoissa vai emme. Punainen viiva kaaviossa HTTP-pyynnön viive näyttää SLO:n kohdalla 60 ms. Viiva osoittaa, että olemme selvästi alle maksimivasteaikamme.

Katsotaanpa kustannuspuolta:

10000 50 pyyntöä sekunnissa / 200 pyyntöä palvelinta kohden = 1 palvelinta + XNUMX

Voimme vielä parantaa tätä lukua.

500 pyyntöä sekunnissa

Mielenkiintoisempia asioita alkaa tapahtua, kun kuorma nousee 500 pyyntöön sekunnissa:

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Jälleen vasemmassa yläkulmassa olevasta kaaviosta näet, että sovellus tallentaa normaalia kuormitusta. Jos näin ei ole, palvelimessa, jossa sovellus on käynnissä, on ongelma. Vastauksen latenssikaavio sijaitsee oikeassa yläkulmassa, ja se osoittaa, että 500 pyyntöä sekunnissa johti 25–40 ms:n vastausviiveeseen. 99. prosenttipiste sopii edelleen hienosti yllä valittuun 60 ms SLO:han.

Kustannusten suhteen:

10000 500 pyyntöä sekunnissa / 20 pyyntöä palvelinta kohden = 1 palvelinta + XNUMX

Kaikkea voi vielä parantaa.

1000 pyyntöä sekunnissa

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Hieno lanseeraus! Sovellus osoittaa, että se käsitteli 1000 pyyntöä sekunnissa, mutta SLO rikkoi latenssirajaa. Tämä näkyy rivillä p99 oikeassa yläkulmassa. Huolimatta siitä, että p100-linja on paljon korkeampi, todelliset viiveet ovat suurempia kuin maksimi 60 ms. Sukellaan profilointiin saadaksesi selville, mitä sovellus todella tekee.

Profilointi

Profilointia varten asetamme kuormitukseksi 1000 pyyntöä sekunnissa ja käytä sitten pprof tallentaa tietoja saadaksesi selville, missä sovellus kuluttaa suorittimen aikaa. Tämä voidaan tehdä aktivoimalla HTTP-päätepiste pprof, ja tallenna sitten tulokset kuormitettuna curl-toiminnolla:

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

Tulokset voidaan näyttää näin:

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

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Kaavio näyttää missä ja kuinka paljon sovellus käyttää CPU-aikaa. Kuvauksesta alkaen Brendan Gregg:

X-akseli on pinoprofiilin populaatio aakkosjärjestyksessä (tämä ei ole aika), Y-akseli näyttää pinon syvyyden laskettuna nollasta [ylhäällä]. Jokainen suorakulmio on pinokehys. Mitä leveämpi kehys, sitä useammin se on pinoissa. Se, mikä on päällä, toimii suorittimella, ja alla olevat ovat alielementtejä. Värit eivät yleensä tarkoita mitään, vaan ne valitaan satunnaisesti kehysten erottamiseksi.

Analyysi - hypoteesi

Virityksen osalta keskitymme etsimään hukattua prosessoriaikaa. Etsimme suurimmat turhan kulutuksen lähteet ja poistamme ne. No, koska profilointi paljastaa erittäin tarkasti, missä sovellus tarkalleen kuluttaa prosessoriaikaansa, saatat joutua tekemään sen useita kertoja, ja sinun on myös muutettava sovelluksen lähdekoodia, suoritettava testit uudelleen ja varmistettava, että suorituskyky lähestyy tavoitetta.

Brendan Greggin suositusten mukaisesti luemme kaavion ylhäältä alas. Jokaisella rivillä näkyy pinokehys (funktiokutsu). Ensimmäinen rivi on ohjelman sisääntulopiste, kaikkien muiden kutsujen yläpää (toisin sanoen, kaikkien muiden puheluiden pinossa on se). Seuraava rivi on jo erilainen:

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Jos viet hiiren osoittimen funktion nimen päälle kaaviossa, kokonaisaika, jonka se oli pinossa virheenkorjauksen aikana, tulee näkyviin. HTTPServe-toiminto oli siellä 65% ajasta, muut ajonaikaiset toiminnot runtime.mcall, mstart и gc, vei loppuajan. Hauska tosiasia: 5 % kokonaisajasta käytetään DNS-kyselyihin:

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Ohjelman etsimät osoitteet kuuluvat Postgresql:iin. Klikkaa FindByAge:

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Mielenkiintoista on, että ohjelma osoittaa, että periaatteessa on kolme päälähdettä, jotka lisäävät viiveitä: yhteyksien avaaminen ja sulkeminen, tietojen pyytäminen ja yhteyden muodostaminen tietokantaan. Kaavio osoittaa, että DNS-pyynnöt, yhteyksien avaaminen ja sulkeminen vievät noin 13 % kokonaissuoritusajasta.

Hypoteesi: Yhteyksien uudelleenkäytön yhdistämisen avulla pitäisi lyhentää yhden HTTP-pyynnön aikaa, mikä mahdollistaa suuremman suorituskyvyn ja pienemmän viiveen.

Sovelluksen määrittäminen - kokeilu

Päivitämme lähdekoodin, yritämme poistaa yhteyden Postgresqliin jokaisen pyynnön kohdalla. Ensimmäinen vaihtoehto on käyttää yhteys allas sovellustasolla. Tässä kokeessa me laitetaan se pystyyn yhteyden yhdistäminen sql-ohjaimella go:

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

if err != nil {
   return nil, err
}

Toteutus, tarkkailu, analyysi

Kun testi on käynnistetty uudelleen 1000 pyynnöllä sekunnissa, on selvää, että p99:n latenssitasot ovat palanneet normaaliksi 60 ms:n SLO:lla!

Mitä maksaa?

10000 1000 pyyntöä sekunnissa / 10 pyyntöä palvelinta kohden = 1 palvelinta + XNUMX

Tehdään se vielä paremmin!

2000 pyyntöä sekunnissa

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Kuorman tuplaaminen näyttää saman asian, vasemman yläkulman kaavio näyttää, että sovellus onnistuu käsittelemään 2000 pyyntöä sekunnissa, p100 on alle 60 ms, p99 täyttää SLO:n.

Kustannusten suhteen:

10000 2000 pyyntöä sekunnissa / 5 pyyntöä palvelinta kohden = 1 palvelinta + XNUMX

3000 pyyntöä sekunnissa

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Täällä sovellus voi käsitellä 3000 pyyntöä p99-viiveellä alle 60 ms. SLO:ta ei rikota, ja kustannukset hyväksytään seuraavasti:

10000 3000 pyyntöä sekunnissa / 4 1 pyyntöä per palvelin = XNUMX palvelinta + XNUMX (kirjoittaja on kääntänyt noin kääntäjä)

Kokeillaan toista analyysikierrosta.

Analyysi - hypoteesi

Keräämme ja näytämme sovelluksen virheenkorjauksen tulokset 3000 pyyntöä sekunnissa:

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Silti 6 % ajasta kuluu yhteyksien luomiseen. Poolin määrittäminen on parantanut suorituskykyä, mutta voit silti nähdä, että sovellus jatkaa uusien yhteyksien luomista tietokantaan.

Hypoteesi: Yhteydet altaan olemassaolosta huolimatta katkeavat ja puhdistetaan, joten sovelluksen on nollattava ne. Odottavien yhteyksien määrän asettaminen poolin koon mukaan auttaa vähentämään viivettä minimoimalla ajan, jonka sovellus käyttää yhteyden luomiseen.

Sovelluksen määrittäminen - kokeilu

Yritetään asentaa MaxIdleConns yhtä suuri kuin uima-altaan koko (kuvattu myös täällä):

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

Toteutus, tarkkailu, analyysi

3000 pyyntöä sekunnissa

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

p99 on alle 60 ms huomattavasti pienemmällä p100:lla!

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Liekkikäyrän tarkistaminen osoittaa, että yhteyttä ei enää havaita! Tarkastellaanpa tarkemmin pg(*conn).query - Emme myöskään huomaa yhteyden muodostumista täällä.

SRE: Suorituskykyanalyysi. Asennusmenetelmä käyttämällä yksinkertaista verkkopalvelinta Gossa

Johtopäätös

Suorituskykyanalyysi on ratkaisevan tärkeä sen ymmärtämiseksi, että asiakkaiden odotukset ja ei-toiminnalliset vaatimukset täyttyvät. Analyysi vertaamalla havaintoja asiakkaiden odotuksiin voi auttaa määrittämään, mikä on hyväksyttävää ja mikä ei. Go tarjoaa tehokkaat työkalut, jotka on sisäänrakennettu vakiokirjastoon, jotka tekevät analysoinnista yksinkertaista ja helppokäyttöistä.

Lähde: will.com

Lisää kommentti