SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Analiza e performancës dhe konfigurimi — një mjet i fuqishëm për verifikimin e përputhshmërisë së performancës për klientët.

Analiza e performancës mund të përdoret për të identifikuar ngushticat në program, duke aplikuar një qasje shkencore në eksperimentet e konfigurimit. Ky artikel përcakton një qasje të përgjithshme për analizën e performancës dhe konfigurimin duke përdorur si shembull një server web në Go.

Go është veçanërisht i përshtatshëm për këtë, pasi ka mjete profilizimi pprof në bibliotekën standarde.

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Strategjia

Le të krijojmë një listë përmbledhëse për analizën tonë strukturore. Do të përpiqemi të përdorim disa të dhëna për të marrë vendime, në vend që të bëjmë ndryshime të bazuara në intuitë ose supozime. Kështu që do të bëjmë siç vijon:

  • Përcaktojmë kufijtë e optimizimit (kërkesat);
  • Llogaritni ngarkesën transaksionale për sistemin;
  • Kryejmë testin (krijojmë të dhëna);
  • Vëzhgojmë;
  • Analizojmë — a plotësohen të gjitha kërkesat?
  • Konfigurojmë në mënyrë shkencore, krijojmë një hipotezë;
  • Pohojme një eksperiment për të verifikuar këtë hipotezë.

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Arkitektura e një serveri HTTP të thjeshtë

Për këtë artikull do të përdorim një server HTTP të vogël në Golang. Të gjithë kodin e këtij artikulli mund ta gjeni këtu.

Aplikacioni i analizuar është një server HTTP që interesohet me Postgresql për çdo kërkesë. Për më tepër, kemi Prometheus, node_exporter dhe Grafana për mbledhjen dhe paraqitjen e metrikave të aplikacionit dhe sistemit.

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Për thjeshtësim, le të supozojmë se për shkallëzimin horizontal (dhe për thjeshtësimin e llogaritjeve) çdo shërbim dhe bazë të dhënash vendoset së bashku:

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Përcaktoni qëllimet

Në këtë hap, përcaktojmë qëllimin. Çfarë po përpiqemi të analizojmë? Si do ta dimë se është koha për të përfunduar? Në këtë artikull do të paraqesim se kemi klientë dhe që shërbimi ynë do të përpunojë 10,000 kërkesa në sekondë.

Google SRE Book Më pas do të shqyrtojmë mënyrat e zgjedhjes dhe modelimit. Do të veprojmë ashtu, do të ndërtoshim modele:

  • Kohëzgjatja: 99% e kërkesave duhet të realizohen brenda 60 ms;
  • Kostoja: shërbimi duhet të konsumojë një shumë minimale parash, e cila na duket arsyeshëm e mundshme. Për këtë, maksimizojmë kapacitetin.
  • Planifikimi i kapaciteteve: nevojitet një kuptim dhe dokumentim se sa kopje të aplikacionit do të nevojiten për të filluar, duke përfshirë funksionin e përgjithshëm të shkallëzimit, si dhe sa kopje do të nevojiten për të përmbushur kërkesat fillestare të ngarkesës dhe për të siguruar redundancë n+1.

Vonesa mund të kërkojë optimizim përveç analizës, por kapaciteti duhet të analizohet qartë. Duke përdorur procesin SRE SLO, kërkesa për vonesën vjen nga klienti ose biznesi, siç paraqitet nga pronari i produktit. Dhe shërbimi ynë do ta përmbushë këtë angazhim nga fillimi pa ndonjë konfigurim!

Konfigurimi i mjedisit të testimit

Me anë të mjedisit të testimit, ne do të jemi në gjendje të japim një ngarkesë të dozimit në sistemin tonë. Do të krijohen të dhëna për analizën e performancës së shërbimeve në internet.

Ngarkesa transaksionale

Ky mjedis përdor Vegeta për të krijuar një frekuencë të personalizueshme të kërkesave HTTP, deri sa të ndalet:

$ 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

Vëzhgimi

Gjatë ekzekutimit do të aplikohet një ngarkesë transaksionale. Përveç metrikeve të aplikacionit (numri i kërkesave, vonesat në përgjigje) dhe sistemit operativ (memoria, CPU, IOPS), do të nisë profilizimi i aplikacionit për të kuptuar se ku ka probleme dhe si shpenzohet koha e procesorit.

Profilizimi

Profilizimi është një lloj matje që lejon të shikoni se ku shkel koha e procesorit gjatë funksionimit të aplikacionit. Ai përcakton se ku dhe sa shumë shpenzohet koha e procesorit:

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Këto të dhëna mund të përdoren gjatë analizës për të fituar një ide se cila kohë e procesorit është e humbur dhe cila punë është e panevojshme. Go (pprof) mund të gjenerojë profile dhe t'i vizualizojë ato si grafikë flakë, duke përdorur një set standard mjetesh. Do t'i flas për përdorimin e tyre dhe udhëzimet për konfigurimin më poshtë në artikull.

Ekzekutimi, vëzhgimi, analiza.

Do të realizojmë një eksperiment. Ne do të kryejmë, vëzhgojmë dhe analizojmë derisa të jemi të kënaqur me performancën. Do të zgjedhim një ngarkesë të ulët në mënyrë rastësore për ta aplikuar për të marrë rezultatet e vëzhgimeve të para. Në çdo hap tjetër, do të rrisim ngarkesën me një faktor shtesë të përzgjedhur me një shkallë të caktuar. Çdo ekzekutim të testimit të ngarkesës kryhet me rregullimin e numrit të kërkesave: make load-test LOAD_TEST_RATE=X.

50 kërkesa në sekondë

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Vini re dy grafikat e sipërme. Grafiku në të majtë tregon se aplikacioni ynë po përpunon 50 kërkesa në sekondë (sipas mendimit të tij), ndërsa grafiku në të djathtë tregon kohën e çdo kërkese. Të dy parametrat na ndihmojnë të shohim dhe të analizojmë: a e arrijmë kufirin tonë të performancës apo jo. Linja e kuqe në grafikun HTTP Request Latency tregon SLO në 60ms. Nga linja e grafikut, shihet se jemi shumë më poshtë se koha jonë maksimale e përgjigjes.

Të shohim nga ana e kostove:

10000 kërkesa në sekondë / për 50 kërkesa për server = 200 serverë + 1

Ne akoma mund ta përmirësojmë këtë tregues.

500 kërkesa në sekondë

Gjërat më interesante fillojnë të ndodhin kur ngarkesa arrin 500 kërkesa në sekondë:

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Sërish në grafikën në këndin e sipërm të majtë, duket se aplikacioni regjistron një ngarkesë normale. Nëse nuk është kështu, ka një problem me serverin ku është i instaluar aplikacioni. Grafiku me vonesën e përgjigjes, i vendosur në faqen e sipërme të djathtë, tregon se 500 kërkesa në sekondë kanë shkaktuar një vonesë përgjigje prej 25-40ms. 99 percentili ende qëndron mirë brenda SLO prej 60ms, të zgjedhur më sipër.

Nga pikëpamja e kostos:

10000 kërkesa në sekondë / 500 kërkesa për server = 20 serverë + 1

Ende ka vend për përmirësim.

1000 kërkesa në sekondë

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Start i shkëlqyer! Aplikacioni tregon se ka procesuar 1000 kërkesa në sekondë, megjithatë kufiri i vonesës është kaluar nga ana e SLO. Kjo duket nga linja p99 në grafikën e sipërme të djathtë. Megjithëse linja p100 është shumë më lartë, vonesat reale janë më të larta se maksimumi prej 60ms. Le të hedhim një vështrim në profilizim për të zbuluar se çfarë po bën në të vërtetë aplikacioni.

Profilizimi

Për profilizim, ne vendosim ngarkesën në 1000 kërkesa në sekondë, pastaj përdorim pprof për të marrë të dhëna, për të kuptuar se ku aplikacioni po shpenzon kohën e procesorit. Kjo mund të bëhet duke aktivizuar HTTP endpoint pprof, pas së cilës, gjatë ngarkesës, ruani rezultatet duke përdorur curl:

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

Rezultatet mund të shfaqen kështu:

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

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Grafiku tregon se ku dhe sa kohë procesori po shpenzon aplikacioni. Nga përshkrimi i Brendan Gregg:

Në boshtin X – mbushja e profilit të grumbullit, të renditur alfabetikisht (kjo nuk është kohë), boshti Y tregon thellësinë e grumbullit, duke filluar nga zero në [top]. Çdo drejtkëndësh është një kadër i grumbullit. Sa më i gjerë të jetë kadrin, aq më shpesh është ai në grumbuj. Ajo që është në krye – punon në CPU, ndërsa poshtë janë elementët fëmijë. Ngjyrat zakonisht nuk kanë kuptim, ato thjesht zgjidhen rastësisht për të dalluar kadrin.

Analiza – hipoteza

Për konfigurimin, ne do të përqendrohemi në përpjekjen për të gjetur shpenzimet e panevojshme të kohës së procesorit. Do të kërkojmë burimet më të mëdha të shpenzimeve të panevojshme dhe do t’i heqim ato. Në lidhje me faktin se profilizimi zbulon me saktësi se ku aplikacioni po shpenzon kohën e tij të procesorit, ndoshta do të nevojitet ta bëni këtë disa herë, gjithashtu do të kërkohet të ndryshoni kodin burimor të aplikacionit, të rinisni testet dhe të vëreni se si performanca afron atë që është planifikuar.

Duke ndjekur rekomandimet e Brendan Gregg, do të lexojmë grafikën nga lart poshtë. Çdo rresht paraqet një kadër steku (thirrje funksioni). Rreshti i parë është pika e hyrjes në program, prindi i të gjitha thirrjeve të tjera (në fjalë të tjera, të gjitha thirrjet e tjera do ta kenë atë në stek). Rreshti tjetër tashmë ndryshon:

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Nëse poziciononi kursorin mbi emrin e funksionit në grafik, do të shfaqet koha totale sa ka qenë në stek gjatë depurimit. Funksioni HTTPServe ka qenë aty 65% të kohës, funksionet e tjera runtime, runtime.mcall, mstart dhe gc, zënë kohën e mbetur. Fakt i interesant: 5% e kohës totale është shpenzuar në kërkesa DNS:

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Adresat që programi po kërkon i përkasin Postgresql. Klikoni në FindByAge:

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Është interesante, programa tregon se në parim ka tre burime kryesore që shtojnë vonesa: hapja dhe mbyllja e lidhjeve, kërkesa për të dhëna dhe lidhja me bazën e të dhënave. Në grafikun e vendosur, duket se kërkesat për DNS, hapja dhe mbyllja e lidhjeve zënë rreth 13% të tërë kohës së ekzekutimit.

Hipoteza: ripingulimi i lidhjeve me ndihmën e një pooli do të duhet të reduktojë kohën e një kërkese për HTTP, duke lejuar një kapacitet më të lartë dhe vonesa më të ulëta.

Konfigurimi i aplikacionit — eksperiment

Po përditësojmë kodin burimor, duke provuar të heqim lidhjen me Postgresql për çdo kërkesë. Varianti i parë — përdorimi i poolit të lidhjeve në nivelin e aplikacionit. Në këtë eksperiment ne do ta konfiguroni poolin e lidhjeve me ndihmën e driverit sql për go:

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

if err != nil {
   return nil, err
}

Ekzekutimi, vëzhgimi, analiza

Pas rinisjes së testit me 1000 kërkesa në sekondë, vihet re se p99 për vonesat janë rikthyer në normë me SLO 60ms!

Si për çmimin?

10000 kërkesa në sekondë / për 1000 kërkesa në server = 10 serverë + 1

Le të bëjmë edhe më mirë!

2000 kërkesa në sekondë

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Dublimi i ngarkesës tregon të njëjtën gjë; grafiku në qoshen e majtë të sipërm tregon se aplikacioni arrin të përpunojë 2000 kërkesa në sekondë, p100 nën 60ms, p99 përmbush SLO-në.

Nga pikëpamja e kostos:

10000 kërkesa në sekondë / 2000 kërkesa për server = 5 serverë + 1

3000 kërkesa në sekondë

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Këtu aplikacioni mund të përpunojë 3000 kërkesa me vonesë p99 më pak se 60ms. SLO-ja nuk shkellet, ndërsa kostoja është pranuar siç vijon:

10000 kërkesa në sekondë / 3000 kërkesa për server = 4 serverë + 1 (autori e rrumbullakoi në numrin më të madh, shënim i përkthyesit)

Le të provojmë një raund tjetër analizash.

Analiza – hipoteza

Po mbledhim dhe shfaqim rezultatet e debugut të aplikacionit në 3000 kërkesa në sekondë:

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Akoma 6% e kohës shpenzohet për krijimin e lidhjeve. Konfigurimi i pushtetit përmirësoi performancën, por akoma është e dukshme se aplikacioni vazhdon të punojë për të krijuar lidhje të reja me bazën e të dhënave.

Hipoteza: Lidhjet, megjithëse ekziston një pushtet, akoma hidhesh dhe pastruan, kështu që aplikacioni duhet t'i riinstalojë ato. Vendosja e numrit të lidhjeve në pritje sipas madhësisë së pushtetit duhet të ndihmojë me vonesën duke minimizuar kohën që aplikacioni shpenzon për të krijuar lidhje..

Konfigurimi i aplikacionit — eksperiment

Po provojmë të vendosim MaxIdleConns e barab taj nga pooli (po ashtu e përshkruar këtu):

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

Ekzekutimi, vëzhgimi, analiza

3000 kërkesa në sekondë

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

p99 më pak se 60ms me një p100 shumë më të ulët!

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Kontrollimi i grafikëve të flakës tregon se vendosja e lidhjes nuk është më e dukshme! Po kontrollojmë më në detaje pg(*conn).query — gjithashtu nuk vërejmë vendosjen e lidhjes këtu.

SRE: Analiza e performancës. Një metodë për konfigurim duke përdorur një server web të thjeshtë në Go

Përfundimi

Analiza e performancës është thelbësore për të kuptuar se pritjet e klientëve dhe kërkesat e papërfishta janë përmbushur. Analiza duke krahasuar vëzhgimet me pritjet e klientëve mund të ndihmojë në përcaktimin e asaj që është e pranueshme dhe asaj që nuk është. Go ofron mjete të efektshme, të integruara në bibliotekën standarde, që e bëjnë analizën të thjeshtë dhe të arritshme.

Burimi: habr.com

Bli një hosting të besueshëm për faqet me mbrojtje DDoS, VPS VDS serverë 🔥 Bli një hosting të besueshëm për faqet me mbrojtje DDoS, VPS VDS serverë | ProHoster