SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Կատարման վերլուծությունը և թյունինգը հզոր գործիք է հաճախորդների համար կատարողականի համապատասխանությունը ստուգելու համար:

Արդյունավետության վերլուծությունը կարող է օգտագործվել ծրագրում խոչընդոտների առկայությունը ստուգելու համար՝ կիրառելով գիտական ​​մոտեցում թյունինգային փորձերի փորձարկման համար: Այս հոդվածը սահմանում է կատարողականի վերլուծության և թյունինգի ընդհանուր մոտեցում՝ որպես օրինակ օգտագործելով Go վեբսերվերը:

Go-ն այստեղ հատկապես լավ է, քանի որ այն ունի պրոֆիլավորման գործիքներ pprof ստանդարտ գրադարանում:

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

ստրատեգիա

Եկեք ստեղծենք ամփոփ ցուցակ մեր կառուցվածքային վերլուծության համար: Մենք կփորձենք օգտագործել որոշ տվյալներ որոշումներ կայացնելու համար՝ ինտուիցիայի կամ ենթադրությունների հիման վրա փոփոխություններ կատարելու փոխարեն: Դա անելու համար մենք կանենք հետևյալը.

  • Մենք որոշում ենք օպտիմալացման սահմանները (պահանջները);
  • Մենք հաշվարկում ենք գործարքի բեռը համակարգի համար.
  • Մենք կատարում ենք թեստը (ստեղծում ենք տվյալներ);
  • Մենք դիտարկում ենք;
  • Մենք վերլուծում ենք. բոլոր պահանջները բավարարվա՞ծ են:
  • Գիտականորեն դրել ենք, վարկած ենք անում.
  • Այս վարկածը ստուգելու համար մենք կատարում ենք փորձ:

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Պարզ HTTP սերվերի ճարտարապետություն

Այս հոդվածի համար մենք կօգտագործենք փոքր HTTP սերվեր Գոլանգում: Այս հոդվածի բոլոր ծածկագրերը կարելի է գտնել այստեղ.

Վերլուծվող հավելվածը HTTP սերվեր է, որը հարցում է անում Postgresql-ի յուրաքանչյուր հարցում: Բացի այդ, կան Prometheus, node_exporter և Grafana հավելվածների և համակարգի չափումները հավաքելու և ցուցադրելու համար:

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Պարզեցնելու համար մենք համարում ենք, որ հորիզոնական մասշտաբի (և հաշվարկների պարզեցման) համար յուրաքանչյուր ծառայություն և տվյալների բազա տեղադրվում են միասին.

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Նպատակների սահմանում

Այս քայլով մենք որոշում ենք նպատակը։ Ի՞նչ ենք մենք փորձում վերլուծել։ Ինչպե՞ս կարող ենք իմանալ, թե երբ է ավարտվելու ժամանակը: Այս հոդվածում մենք կպատկերացնենք, որ ունենք հաճախորդներ, և որ մեր ծառայությունը վայրկյանում կմշակի 10 հարցում:

В Google SRE Գիրք Ընտրության և մոդելավորման մեթոդները մանրամասն քննարկվում են: Եկեք նույնն անենք և կառուցենք մոդելներ.

  • Հետաձգվածություն. հարցումների 99%-ը պետք է կատարվի 60մ-ից պակաս ժամանակում;
  • Արժեքը. Ծառայությունը պետք է ծախսի այն նվազագույն գումարը, որը մենք կարծում ենք ողջամտորեն հնարավոր է: Դա անելու համար մենք առավելագույնի ենք հասցնում թողունակությունը.
  • Տարողությունների պլանավորում. Պահանջում է հասկանալ և փաստաթղթավորել, թե հավելվածի քանի օրինակ պետք է գործարկվի, ներառյալ մասշտաբավորման ընդհանուր ֆունկցիոնալությունը, և քանի օրինակ կպահանջվի նախնական բեռնվածության և մատակարարման պահանջները բավարարելու համար: ավելորդություն n+1.

Լատենտությունը վերլուծությունից բացի կարող է պահանջել օպտիմալացում, բայց թողունակությունը հստակ պետք է վերլուծվի: SRE SLO գործընթացն օգտագործելիս հետաձգման հարցումը գալիս է հաճախորդից կամ բիզնեսից՝ ներկայացված ապրանքի սեփականատիրոջ կողմից: Եվ մեր ծառայությունն այդ պարտավորությունը կկատարի ի սկզբանե առանց որևէ կարգավորումների։

Թեստային միջավայրի ստեղծում

Փորձարկման միջավայրի օգնությամբ մենք կկարողանանք դոզավորված բեռ տեղադրել մեր համակարգի վրա: Վերլուծության համար կստեղծվեն տվյալներ վեբ ծառայության աշխատանքի վերաբերյալ:

Գործարքի ծանրաբեռնվածություն

Այս միջավայրը օգտագործում է Բուսա ստեղծել անհատական ​​HTTP հարցման տոկոսադրույք մինչև դադարեցնելը՝

$ 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

Դիտարկում

Գործարքի բեռը կկիրառվի գործարկման ժամանակ: Հավելվածի չափորոշիչներից (հարցումների քանակ, պատասխանների հետաձգումներ) և օպերացիոն համակարգից (հիշողություն, պրոցեսոր, IOPS), կսկսվի հավելվածի պրոֆիլավորումը՝ հասկանալու, թե որտեղ է այն խնդիրներ, ինչպես նաև ինչպես է ծախսվում պրոցեսորի ժամանակը:

Պրոֆիլավորում

Պրոֆիլավորումը չափման մի տեսակ է, որը թույլ է տալիս տեսնել, թե ուր է գնում պրոցեսորի ժամանակը, երբ հավելվածն աշխատում է: Այն թույլ է տալիս ճշգրիտ որոշել, թե որտեղ և որքան ժամանակ է ծախսվել պրոցեսորի վրա.

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Այս տվյալները կարող են օգտագործվել վերլուծության ընթացքում՝ պատկերացում կազմելու պրոցեսորի վատնված ժամանակի և կատարվող անհարկի աշխատանքի մասին: Go (pprof) կարող է ստեղծել պրոֆիլներ և դրանք պատկերացնել որպես բոցավառ գրաֆիկներ՝ օգտագործելով ստանդարտ գործիքների հավաքածու: Ես կխոսեմ դրանց օգտագործման և տեղադրման ուղեցույցի մասին ավելի ուշ հոդվածում:

Կատարում, դիտարկում, վերլուծություն:

Եկեք փորձ անենք։ Մենք կկատարենք, կդիտարկենք, կվերլուծենք այնքան ժամանակ, քանի դեռ չենք բավարարվել ներկայացմամբ։ Եկեք ընտրենք կամայականորեն ցածր բեռի արժեք՝ այն կիրառելու համար՝ առաջին դիտարկումների արդյունքները ստանալու համար: Յուրաքանչյուր հաջորդ քայլում մենք կավելացնենք բեռը որոշակի մասշտաբային գործակցով, որը ընտրված է որոշակի տատանումներով: Բեռի փորձարկման յուրաքանչյուր գործարկում կատարվում է ճշգրտված հարցումների քանակով. make load-test LOAD_TEST_RATE=X.

50 հարցում վայրկյանում

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Ուշադրություն դարձրեք վերևի երկու գծապատկերներին: Վերևի ձախ կողմը ցույց է տալիս, որ մեր դիմումը վայրկյանում մշակում է 50 հարցում (կարծում է), իսկ վերևի աջը ցույց է տալիս յուրաքանչյուր հարցման տևողությունը: Երկու պարամետրերն էլ օգնում են մեզ նայել և վերլուծել՝ արդյոք մենք գտնվում ենք մեր կատարողականի սահմաններում, թե ոչ: Կարմիր գիծ գրաֆիկի վրա HTTP-ի հարցում ուշացում ցույց է տալիս SLO-ն 60 ms-ով: Գիծը ցույց է տալիս, որ մենք շատ ցածր ենք մեր առավելագույն արձագանքման ժամանակից:

Դիտարկենք ծախսերի կողմը.

10000 հարցում մեկ վայրկյանում / 50 հարցում մեկ սերվերի համար = 200 սերվեր + 1

Մենք դեռ կարող ենք բարելավել այս ցուցանիշը:

500 հարցում վայրկյանում

Ավելի հետաքրքիր բաներ սկսում են տեղի ունենալ, երբ բեռը հասնում է վայրկյանում 500 հարցումների.

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Կրկին վերևի ձախ գրաֆիկում դուք կարող եք տեսնել, որ հավելվածը գրանցում է նորմալ բեռնվածություն: Եթե ​​դա այդպես չէ, խնդիր կա սերվերի վրա, որի վրա աշխատում է հավելվածը: Արձագանքների հետաձգման գրաֆիկը գտնվում է վերևի աջ մասում՝ ցույց տալով, որ վայրկյանում 500 հարցումը հանգեցրել է պատասխանի 25-40 մվ ուշացման: 99-րդ ցենտիլը դեռ լավ տեղավորվում է վերը ընտրված 60ms SLO-ի մեջ:

Արժեքի առումով.

10000 հարցում մեկ վայրկյանում / 500 հարցում մեկ սերվերի համար = 20 սերվեր + 1

Ամեն ինչ դեռ կարելի է բարելավել։

1000 հարցում վայրկյանում

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Հիանալի մեկնարկ: Հավելվածը ցույց է տալիս, որ այն մշակել է վայրկյանում 1000 հարցում, սակայն ուշացման սահմանը խախտվել է SLO-ի կողմից։ Սա կարելի է տեսնել p99 տողում՝ վերևի աջ գրաֆիկում: Չնայած այն հանգամանքին, որ p100 գիծը շատ ավելի բարձր է, փաստացի ուշացումները ավելի բարձր են, քան առավելագույնը 60 մվ: Եկեք սուզվենք պրոֆիլավորման մեջ՝ պարզելու, թե իրականում ինչ է անում հավելվածը:

Պրոֆիլավորում

Պրոֆիլավորման համար մենք բեռը սահմանել ենք վայրկյանում 1000 հարցում, այնուհետև օգտագործում ենք pprof տվյալների հավաքագրման համար՝ պարզելու, թե որտեղ է հավելվածը ծախսում պրոցեսորի ժամանակը: Դա կարելի է անել՝ ակտիվացնելով HTTP վերջնակետը pprof, և այնուհետև, ծանրաբեռնվածության տակ, պահպանեք արդյունքները՝ օգտագործելով curl:

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

Արդյունքները կարող են ցուցադրվել այսպես.

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

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Գրաֆիկը ցույց է տալիս, թե որտեղ և որքան է հավելվածը ծախսում պրոցեսորի ժամանակ: Սկսած նկարագրությունից Բրենդան Գրեգ:

X առանցքը կույտի պրոֆիլի պոպուլյացիան է՝ դասավորված այբբենական կարգով (ժամանակը չէ), Y առանցքը ցույց է տալիս կույտի խորությունը՝ զրոյից հաշվելով [վերևում]: Յուրաքանչյուր ուղղանկյուն կույտ շրջանակ է: Որքան լայն է շրջանակը, այնքան ավելի հաճախ այն առկա է կույտերում: Այն, ինչ վերևում է, աշխատում է պրոցեսորի վրա, իսկ ներքևում գտնվողը երեխայի տարրերն են: Գույները սովորաբար ոչինչ չեն նշանակում, այլ պարզապես ընտրվում են պատահականորեն՝ շրջանակները տարբերելու համար:

Վերլուծություն - վարկած

Կարգավորման համար մենք կկենտրոնանանք պրոցեսորի կորցրած ժամանակը գտնելու վրա: Մենք կփնտրենք անօգուտ ծախսերի ամենամեծ աղբյուրները և կվերացնենք դրանք։ Դե, հաշվի առնելով, որ պրոֆիլավորումը շատ ճշգրիտ բացահայտում է, թե կոնկրետ որտեղ է ծրագիրը ծախսում իր պրոցեսորի ժամանակը, դուք կարող եք դա անել մի քանի անգամ, ինչպես նաև պետք է փոխեք հավելվածի սկզբնական կոդը, կրկնեք թեստերը և տեսնեք, որ կատարումը մոտենում է նպատակին:

Հետևելով Բրենդան Գրեգի առաջարկություններին, մենք կկարդանք աղյուսակը վերևից ներքև: Յուրաքանչյուր տող ցուցադրում է կույտի շրջանակ (ֆունկցիայի կանչ): Առաջին տողը ծրագրի մուտքի կետն է, մյուս բոլոր զանգերի մայրը (այլ կերպ ասած, մնացած բոլոր զանգերն այն կունենան իրենց փաթեթում): Հաջորդ տողն արդեն տարբեր է.

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Եթե ​​կուրսորը սավառնել եք գծապատկերում գտնվող ֆունկցիայի անվան վրա, ապա կցուցադրվի վրիպազերծման ընթացքում այն ​​բուրգի վրա եղած ընդհանուր ժամանակը: HTTPServe ֆունկցիան եղել է ժամանակի 65%-ում, գործարկման ժամանակի այլ գործառույթներ runtime.mcall, mstart и gc, վերցրեց մնացած ժամանակը: Զվարճալի փաստ. ընդհանուր ժամանակի 5%-ը ծախսվում է DNS հարցումների վրա.

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Հասցեները, որոնք ծրագիրը փնտրում է, պատկանում են Postgresql-ին։ Սեղմեք FindByAge:

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Հետաքրքիր է, որ ծրագիրը ցույց է տալիս, որ, սկզբունքորեն, կան երեք հիմնական աղբյուրներ, որոնք ավելացնում են ուշացումները՝ կապերի բացում և փակում, տվյալների հարցում և տվյալների բազայի միացում: Գրաֆիկը ցույց է տալիս, որ DNS հարցումները, կապերի բացումը և փակումը զբաղեցնում են կատարման ընդհանուր ժամանակի մոտ 13%-ը:

Վարկած. Միացումների միջոցով միացումների վերօգտագործումը պետք է նվազեցնի մեկ HTTP հարցման ժամանակը, ինչը թույլ կտա ավելի բարձր թողունակություն և ավելի ցածր ուշացում:.

Հավելվածի կարգավորում՝ փորձ

Մենք թարմացնում ենք ելակետային կոդը, փորձում ենք հեռացնել կապը Postgresql-ի հետ յուրաքանչյուր հարցման համար: Առաջին տարբերակը օգտագործելն է կապի լողավազան կիրառման մակարդակում: Այս փորձի ժամանակ մենք եկեք կարգավորենք այն կապի միավորում՝ օգտագործելով sql դրայվեր go-ի համար.

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

if err != nil {
   return nil, err
}

Կատարում, դիտարկում, վերլուծություն

Թեստը վայրկյանում 1000 հարցումով վերսկսելուց հետո պարզ է, որ p99-ի հետաձգման մակարդակները վերադարձել են նորմալ՝ 60 մս SLO-ով:

Ի՞նչ արժե:

10000 հարցում մեկ վայրկյանում / 1000 հարցում մեկ սերվերի համար = 10 սերվեր + 1

Եկեք դա անենք նույնիսկ ավելի լավ:

2000 հարցում վայրկյանում

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Բեռի կրկնապատկումը ցույց է տալիս նույն բանը, վերևի ձախ գրաֆիկը ցույց է տալիս, որ հավելվածը կարողանում է վայրկյանում մշակել 2000 հարցում, p100-ը 60ms-ից ցածր է, p99-ը բավարարում է SLO-ին։

Արժեքի առումով.

10000 հարցում մեկ վայրկյանում / 2000 հարցում մեկ սերվերի համար = 5 սերվեր + 1

3000 հարցում վայրկյանում

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Այստեղ հավելվածը կարող է մշակել 3000 հարցում՝ 99 մվ-ից պակաս p60 ուշացումով: SLO-ն չի խախտվում, իսկ արժեքը ընդունվում է հետևյալ կերպ.

10000 հարցում վայրկյանում / 3000 հարցում մեկ սերվերի համար = 4 սերվեր + 1 (հեղինակը ամփոփել է. մոտ. թարգմանիչ)

Փորձենք վերլուծության ևս մեկ փուլ։

Վերլուծություն - վարկած

Մենք հավաքում և ցուցադրում ենք հավելվածի վրիպազերծման արդյունքները վայրկյանում 3000 հարցումով.

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Դեռևս ժամանակի 6%-ը ծախսվում է կապեր հաստատելու վրա։ Լողավազանի կարգավորումը բարելավեց արդյունավետությունը, բայց դուք դեռ կարող եք տեսնել, որ հավելվածը շարունակում է աշխատել տվյալների բազայի հետ նոր կապեր ստեղծելու վրա:

Վարկած. Միացումները, չնայած լողավազանի առկայությանը, դեռևս անջատված և մաքրված են, ուստի հավելվածը պետք է վերակայի դրանք: Սպասող կապերի քանակը լողավազանի չափին սահմանելը պետք է օգնի հետաձգմանը` նվազագույնի հասցնելով հավելվածի ծախսած ժամանակը կապ ստեղծելու համար:.

Հավելվածի կարգավորում՝ փորձ

Փորձում է տեղադրել MaxIdleConns հավասար է լողավազանի չափին (նաև նկարագրված է այստեղ):

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

Կատարում, դիտարկում, վերլուծություն

3000 հարցում վայրկյանում

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

p99-ը 60ms-ից պակաս է, իսկ p100-ը զգալիորեն պակաս է:

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Ֆլեյմի գրաֆիկի ստուգումը ցույց է տալիս, որ կապն այլևս նկատելի չէ: Եկեք ստուգենք ավելի մանրամասն pg(*conn).query — Մենք նույնպես չենք նկատում, որ կապ է հաստատվում այստեղ։

SRE: Performance Analysis. Կազմաձևման մեթոդ՝ օգտագործելով պարզ վեբ սերվեր Go-ում

Ամփոփում

Արդյունավետության վերլուծությունը չափազանց կարևոր է հասկանալու համար, որ հաճախորդների սպասելիքները և ոչ ֆունկցիոնալ պահանջները բավարարվում են: Դիտարկումները հաճախորդի ակնկալիքների հետ համեմատելով վերլուծությունը կարող է օգնել որոշել, թե որն է ընդունելի և ինչը ոչ: Go-ն ապահովում է հզոր գործիքներ, որոնք ներկառուցված են ստանդարտ գրադարանում, որոնք վերլուծությունը դարձնում են պարզ և մատչելի:

Source: www.habr.com

Добавить комментарий