PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Զեկույցում ներկայացված են մի քանի մոտեցումներ, որոնք թույլ են տալիս վերահսկել SQL հարցումների կատարումը, երբ դրանք օրական միլիոնավոր են, և կան հարյուրավոր վերահսկվող PostgreSQL սերվերներ:

Տեխնիկական ի՞նչ լուծումներ են թույլ տալիս արդյունավետ մշակել տեղեկատվության նման ծավալը, և ինչպե՞ս է դա հեշտացնում սովորական մշակողի կյանքը:


Ո՞վ է հետաքրքրված: կոնկրետ խնդիրների և օպտիմիզացման տարբեր տեխնիկայի վերլուծություն SQL հարցումներ և տիպիկ DBA խնդիրների լուծում PostgreSQL-ում - կարող եք նաև կարդալ մի շարք հոդվածներ այս թեմայով:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)
Ես Կիրիլ Բորովիկովն եմ, ներկայացնում եմ Tensor ընկերություն. Մասնավորապես, ես մասնագիտացած եմ մեր ընկերության տվյալների բազաների հետ աշխատելու մեջ:

Այսօր ես ձեզ կասեմ, թե ինչպես ենք մենք օպտիմիզացնում հարցումները, երբ ձեզ հարկավոր չէ «տարանջատել» մեկ հարցման կատարումը, այլ զանգվածաբար լուծել խնդիրը: Երբ կան միլիոնավոր հարցումներ, և դուք պետք է որոշ գտնեք լուծման մոտեցումները այս մեծ խնդիրը.

Ընդհանուր առմամբ, Tensor-ը մեր մեկ միլիոն հաճախորդների համար է VLSI-ն մեր հավելվածն էԿորպորատիվ սոցիալական ցանց, լուծումներ տեսահաղորդակցության համար, ներքին և արտաքին փաստաթղթերի հոսքի համար, հաշվապահական հաշվառման համակարգեր և պահեստներ,... Այսինքն՝ բիզնեսի ինտեգրված կառավարման համար այնպիսի «մեգակոմբինատ», որում կան ավելի քան 100 տարբեր. ներքին նախագծեր։

Ապահովելու համար, որ նրանք բոլորը նորմալ աշխատեն և զարգանան, մենք ունենք 10 զարգացման կենտրոններ ամբողջ երկրում, որոնցում ավելի շատ են 1000 մշակող.

Մենք աշխատում ենք PostgreSQL-ի հետ 2008 թվականից և կուտակել ենք մեր մշակածի մեծ քանակություն՝ հաճախորդի տվյալներ, վիճակագրական, վերլուծական, արտաքին տեղեկատվական համակարգերի տվյալներ. ավելի քան 400 ՏԲ. Միայն արտադրության մեջ կա մոտ 250 սերվեր, և ընդհանուր առմամբ կա մոտ 1000 տվյալների բազայի սերվեր, որոնց մենք վերահսկում ենք։

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

SQL-ը դեկլարատիվ լեզու է: Դուք նկարագրում եք ոչ թե «ինչպես» ինչ-որ բան պետք է աշխատի, այլ «ինչ» եք ուզում հասնել: DBMS-ն ավելի լավ գիտի, թե ինչպես կատարել JOIN՝ ինչպես միացնել ձեր աղյուսակները, ինչ պայմաններ դնել, ինչն անցնելու է ինդեքսով, ինչը չի...

Որոշ DBMS-ներ ընդունում են ակնարկներ. «Ոչ, միացրեք այս երկու աղյուսակները այսինչ հերթում», բայց PostgreSQL-ը չի կարող դա անել: Սա առաջատար ծրագրավորողների գիտակցված դիրքորոշումն է. «Մենք նախընտրում ենք ավարտել հարցումների օպտիմիզատորը, քան թույլ տալ ծրագրավորողներին օգտագործել ինչ-որ ակնարկներ»:

Բայց, չնայած այն հանգամանքին, որ PostgreSQL-ը թույլ չի տալիս «դրսին» կառավարել իրեն, այն հիանալի թույլ է տալիս տեսեք, թե ինչ է կատարվում նրա ներսումերբ դուք կատարում եք ձեր հարցումը և որտեղ այն խնդիրներ ունի:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Ընդհանրապես, ի՞նչ դասական խնդիրների հետ է սովորաբար գալիս ծրագրավորողը [DBA-ին]: «Այստեղ մենք կատարեցինք խնդրանքը, և մեզ մոտ ամեն ինչ դանդաղ է, ամեն ինչ կախված է, ինչ-որ բան է կատարվում... Ինչ-որ փորձանք»:

Պատճառները գրեթե միշտ նույնն են.

  • անարդյունավետ հարցման ալգորիթմ
    Մշակողը․ Բայց հրաշքներ չեն լինում, և նման փոփոխականությամբ ցանկացած համակարգ (10 աղյուսակ մեկում FROM-ից) միշտ ինչ-որ սխալ է տալիս։ [հոդված]
  • հնացած վիճակագրություն
    Այս կետը շատ տեղին է հատկապես PostgreSQL-ի համար, երբ դուք «լցնում» եք մեծ տվյալների բազա սերվերի վրա, հարցում եք անում և այն «սեռականացնում» է ձեր պլանշետը: Որովհետև երեկ դրա մեջ 10 գրառում կար, իսկ այսօր՝ 10 միլիոն, բայց PostgreSQL-ն դեռ տեղյակ չէ այս մասին, և մենք պետք է պատմենք դրա մասին։ [հոդված]
  • «միացնել» ռեսուրսները
    Դուք տեղադրել եք մեծ և ծանրաբեռնված տվյալների բազա թույլ սերվերի վրա, որը չունի բավարար սկավառակ, հիշողություն կամ պրոցեսորի կատարողականություն: Եվ այսքանը... Ինչ-որ տեղ կա կատարողական առաստաղ, որի վերևում այլևս չես կարող ցատկել:
  • արգելափակում
    Սա բարդ կետ է, բայց դրանք առավել արդիական են տարբեր փոփոխող հարցումների համար (ՏԵՂԱԴՐԵԼ, ԹԱՐՄԱՑՆԵԼ, ՋՆԵԼ) - սա առանձին մեծ թեմա է:

Ծրագիր ստանալը

...Իսկ մնացած ամեն ինչի համար մենք պլանի կարիք ունի! Մենք պետք է տեսնենք, թե ինչ է կատարվում սերվերի ներսում:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

PostgreSQL-ի հարցումների կատարման պլանը տեքստի ներկայացման հարցում հարցման կատարման ալգորիթմի ծառ է: Հենց այն ալգորիթմն է, որը պլանավորողի վերլուծության արդյունքում պարզվել է, որ ամենաարդյունավետն է:

Յուրաքանչյուր ծառի հանգույց գործողություն է՝ աղյուսակից կամ ինդեքսից տվյալներ ստանալը, bitmap-ի կառուցումը, երկու աղյուսակների միացումը, ընտրությունը միանալը, հատելը կամ բացառելը: Հարցման կատարումը ներառում է այս ծառի հանգույցների միջով անցնելը:

Հարցման պլան ստանալու համար ամենահեշտ ձևը հայտարարությունը կատարելն է EXPLAIN. Ստանալ բոլոր իրական ատրիբուտներով, այսինքն՝ իրականում կատարել հարցում բազայի վրա. EXPLAIN (ANALYZE, BUFFERS) SELECT ....

Վատ մասը. երբ այն գործարկում ես, դա տեղի է ունենում «այստեղ և հիմա», ուստի այն հարմար է միայն տեղական կարգաբերման համար: Եթե ​​դուք վերցնում եք բարձր բեռնված սերվեր, որը գտնվում է տվյալների մեծ հոսքի տակ, փոխվում է, և տեսնում եք. «Oh! Այստեղ մենք ունենք դանդաղ կատարումxia խնդրանք»: Կես ժամ, մեկ ժամ առաջ. մինչ դուք աշխատում էիք և ստանում էիք այս հարցումը տեղեկամատյաններից, այն հետ բերելով սերվեր, ձեր ամբողջ տվյալների բազան և վիճակագրությունը փոխվեցին: Դուք գործարկում եք այն վրիպազերծելու համար, և այն արագ է աշխատում: Եվ չես կարող հասկանալ՝ ինչու, ինչու էր դանդաղ:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Որպեսզի հասկանանք, թե ինչ է տեղի ունեցել հենց այն պահին, երբ հարցումը կատարվել է սերվերում, խելացի մարդիկ գրել են auto_explain մոդուլ. Այն առկա է գրեթե բոլոր ամենատարածված PostgreSQL բաշխումներում և պարզապես կարող է ակտիվացվել կազմաձևման ֆայլում:

Եթե ​​նա գիտակցում է, որ որոշ հարցումներ ավելի երկար են աշխատում, քան ձեր նշած սահմանաչափը, դա անում է Այս հարցման պլանի «պատկերապատկերը» և դրանք միասին գրում մատյանում.

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Թվում է, թե հիմա ամեն ինչ լավ է, մենք գնում ենք գերան և տեսնում այնտեղ... [տեքստային ոտքի ծածկոց]: Բայց մենք ոչինչ չենք կարող ասել դրա մասին, բացի այն, որ դա հիանալի ծրագիր է, քանի որ դրա իրականացման համար պահանջվել է 11 մվ:

Ամեն ինչ կարծես թե լավ է, բայց ոչինչ պարզ չէ, թե իրականում ինչ է տեղի ունեցել: Բացի ընդհանուր ժամանակից, մենք իրականում ոչինչ չենք տեսնում։ Որովհետև պարզ տեքստի նման «գառին» նայելը հիմնականում տեսողական չէ:

Բայց նույնիսկ եթե դա ակնհայտ չէ, նույնիսկ եթե դա անհարմար է, կան ավելի հիմնարար խնդիրներ.

  • Հանգույցը ցույց է տալիս ամբողջ ենթածառի ռեսուրսների գումարը նրա տակ։ Այսինքն, դուք պարզապես չեք կարող պարզել, թե որքան ժամանակ է ծախսվել այս կոնկրետ ինդեքսի սկանավորման վրա, եթե դրա տակ ինչ-որ տեղավորված պայման կա: Մենք պետք է դինամիկ նայենք՝ տեսնելու, թե ներսում կան «երեխաներ» և պայմանական փոփոխականներ, CTE-ներ, և այս ամենը հանենք «մեր մտքում»:
  • Երկրորդ կետը. այն ժամանակն է, որը նշված է հանգույցի վրա մեկ հանգույցի կատարման ժամանակը. Եթե ​​այս հանգույցն իրականացվել է, օրինակ, մի քանի անգամ աղյուսակի գրառումների միջոցով անցկացման արդյունքում, ապա պլանում ավելանում է օղակների թիվը՝ այս հանգույցի ցիկլերը: Բայց ատոմային կատարման ժամանակը ինքնին մնում է նույնը պլանի առումով։ Այսինքն, որպեսզի հասկանաք, թե ընդհանուր առմամբ որքան ժամանակ է կատարվել այս հանգույցը, դուք պետք է մի բան բազմապատկեք մյուսով, կրկին «ձեր գլխում»:

Նման իրավիճակներում հասկացեք «Ո՞վ է ամենաթույլ օղակը»: գրեթե անհնար է. Հետևաբար, նույնիսկ մշակողները իրենք են գրում «ձեռնարկ»-ում, որ «Պլանը հասկանալը արվեստ է, որը պետք է սովորել, փորձ...».

Բայց մենք ունենք 1000 մշակող, և դուք չեք կարող այս փորձը փոխանցել նրանցից յուրաքանչյուրին: Ես, դու, նա գիտի, բայց այնտեղ ինչ-որ մեկն այլևս չգիտի: Միգուցե նա կսովորի, կամ գուցե ոչ, բայց նա պետք է աշխատի հիմա, և որտեղի՞ց նրան այս փորձը:

Պլանի վիզուալիզացիա

Ուստի մենք հասկացանք, որ այս խնդիրներին դիմակայելու համար անհրաժեշտ է պլանի լավ պատկերացում. [հոդված]

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Մենք առաջին անգամ անցանք «շուկայի միջով», եկեք նայենք ինտերնետին, որպեսզի տեսնենք, թե ինչ կա նույնիսկ:

Բայց պարզվեց, որ շատ քիչ են համեմատաբար «կենդանի» լուծումները, որոնք քիչ թե շատ զարգանում են՝ բառացիորեն՝ միայն մեկը. բացատրել.depesz.com Հուբերտ Լյուբաչևսկու կողմից: Երբ մտնում եք «սնուցման» դաշտ՝ պլանի տեքստային ներկայացում, այն ձեզ ցույց է տալիս վերլուծված տվյալներով աղյուսակ.

  • հանգույցի սեփական մշակման ժամանակը
  • ընդհանուր ժամանակը ամբողջ ենթածառի համար
  • վերցված գրառումների քանակը, որոնք վիճակագրորեն սպասվում էին
  • հանգույցի մարմինն ինքնին

Այս ծառայությունը նաև հնարավորություն ունի կիսել հղումների արխիվը։ Դու այնտեղ գցեցիր քո պլանը և ասացիր. «Հեյ, Վասյա, ահա մի հղում, այնտեղ ինչ-որ բան այն չէ»:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Բայց կան նաև փոքր խնդիրներ.

Նախ, հսկայական քանակությամբ «copy-paste». Դուք վերցնում եք գերանից մի կտոր, կպցնում այնտեղ և նորից ու նորից:

Երկրորդ, ընթերցված տվյալների քանակի վերլուծություն չկա - նույն բուֆերները, որոնք թողարկում են EXPLAIN (ANALYZE, BUFFERS), մենք դա այստեղ չենք տեսնում: Նա պարզապես չգիտի, թե ինչպես դրանք ապամոնտաժել, հասկանալ և աշխատել նրանց հետ: Երբ դուք կարդում եք շատ տվյալներ և հասկանում եք, որ կարող եք սխալ տեղաբաշխել սկավառակը և հիշողության քեշը, այս տեղեկատվությունը շատ կարևոր է:

Երրորդ բացասական կետը այս նախագծի շատ թույլ զարգացումն է։ Պարտավորությունները շատ փոքր են, լավ է, եթե վեց ամիսը մեկ անգամ, իսկ կոդը Perl-ում է:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Բայց սա ամբողջ «բառեր» է, մենք կարող էինք ինչ-որ կերպ ապրել դրա հետ, բայց կա մի բան, որը մեզ մեծապես շեղեց այս ծառայությունից: Սրանք սխալներ են ընդհանուր աղյուսակի արտահայտման (CTE) և տարբեր դինամիկ հանգույցների վերլուծության մեջ, ինչպիսիք են InitPlan/SubPlan-ը:

Եթե ​​հավատում եք այս նկարին, ապա յուրաքանչյուր առանձին հանգույցի կատարման ընդհանուր ժամանակը ավելի մեծ է, քան ամբողջ հարցման կատարման ընդհանուր ժամանակը: Դա պարզ է - Այս CTE-ի առաջացման ժամանակը չի հանվել CTE Scan հանգույցից. Հետևաբար, մենք այլևս չգիտենք ճիշտ պատասխանը, թե որքան ժամանակ է տևել CTE սկանավորումը:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Հետո հասկացանք, որ ժամանակն է գրել մեր սեփականը՝ շտապե՛ք: Յուրաքանչյուր մշակող ասում է. «Հիմա մենք կգրենք մերը, դա շատ հեշտ կլինի»:

Մենք վերցրեցինք վեբ ծառայությունների համար բնորոշ մի կույտ՝ Node.js + Express-ի վրա հիմնված միջուկ, օգտագործեցինք Bootstrap և D3.js՝ գեղեցիկ գծապատկերների համար: Եվ մեր սպասելիքները լիովին արդարացան՝ առաջին նախատիպը ստացանք 2 շաբաթում.

  • հարմարեցված պլանի վերլուծիչ
    Այսինքն, այժմ մենք կարող ենք վերլուծել ցանկացած պլան PostgreSQL-ի կողմից ստեղծվածներից:
  • դինամիկ հանգույցների ճիշտ վերլուծություն - CTE սկան, InitPlan, SubPlan
  • բուֆերների բաշխման վերլուծություն - որտեղ տվյալների էջերը կարդացվում են հիշողությունից, որտեղ տեղական քեշից, որտեղ սկավառակից
  • պարզություն ստացավ
    Որպեսզի այս ամենը չփորենք մատյանում, այլ նկարում անմիջապես տեսնեմ «ամենաթույլ օղակը»։

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Մենք ստացել ենք նման բան՝ ներառելով շարահյուսական ընդգծումը: Բայց սովորաբար մեր մշակողները այլևս չեն աշխատում պլանի ամբողջական ներկայացմամբ, այլ ավելի կարճ: Չէ՞ որ մենք արդեն վերլուծել ենք բոլոր թվերը և նետել աջ ու ձախ, իսկ մեջտեղում թողել ենք միայն առաջին տողը, թե ինչ հանգույց է՝ CTE Scan, CTE սերունդ կամ Seq Scan՝ ըստ ինչ-որ նշանի։

Սա այն կրճատ ներկայացումն է, որը մենք անվանում ենք պլանի ձևանմուշ.

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Էլ ի՞նչը հարմար կլիներ։ Հարմար կլիներ տեսնել, թե որ հանգույցին է հատկացված մեր ընդհանուր ժամանակի մասնաբաժինը, և պարզապես «կպցրեք այն» կողքին: կարկանդակ աղյուսակը.

Մենք մատնացույց ենք անում հանգույցը և տեսնում. պարզվում է, որ Seq Scan-ը խլել է ընդհանուր ժամանակի մեկ քառորդից պակաս, իսկ մնացած 3/4-ը վերցրել է CTE Scan-ը: Սարսափ. Սա փոքրիկ նշում է CTE Scan-ի «կրակի արագության» մասին, եթե դուք ակտիվորեն օգտագործում եք դրանք ձեր հարցումներում: Նրանք այնքան էլ արագ չեն, նրանք զիջում են նույնիսկ սովորական սեղանի սկանավորմանը: [հոդված] [հոդված]

Բայց սովորաբար նման դիագրամներն ավելի հետաքրքիր են, ավելի բարդ, երբ մենք անմիջապես մատնացույց ենք անում մի հատված և տեսնում, օրինակ, որ ժամանակի կեսից ավելին ինչ-որ Seq Scan «կերել է»: Ավելին, ներսում ինչ-որ զտիչ կար, ըստ դրա շատ ձայնագրություններ դեն նետվեցին... Դուք կարող եք ուղղակիորեն նետել այս նկարը ծրագրավորողին և ասել. «Վասյա, այստեղ ամեն ինչ վատ է քեզ համար: Պարզեք, տեսեք, ինչ-որ բան այն չէ:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Բնականաբար, ինչ-որ «ռեյքեր» կային։

Առաջին բանը, որին հանդիպեցինք, կլորացման խնդիրն էր: Պլանում յուրաքանչյուր առանձին հանգույցի ժամանակը նշվում է 1 մկվ ճշգրտությամբ: Եվ երբ հանգույցների ցիկլերի թիվը գերազանցում է, օրինակ, 1000-ը, PostgreSQL-ի կատարումից հետո բաժանվում է «ճշգրտության սահմաններում», ապա հետ հաշվարկելիս մենք ստանում ենք ընդհանուր ժամանակը «ինչ-որ տեղ 0.95 մվ-ից 1.05 մվ-ի միջև»: Երբ հաշվարկը հասնում է միկրովայրկյանների, դա նորմալ է, բայց երբ արդեն [միլի]վայրկյան է, դուք պետք է հաշվի առնեք այս տեղեկատվությունը, երբ ռեսուրսները «բացում» եք «ով ինչքան է սպառել» պլանի հանգույցներին:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Երկրորդ կետը, ավելի բարդ, ռեսուրսների (այդ բուֆերների) բաշխումն է դինամիկ հանգույցների միջև: Սա մեզ արժեցավ նախատիպի առաջին 2 շաբաթը և ևս 4 շաբաթ:

Բավականին հեշտ է ստանալ նման խնդիր. մենք անում ենք CTE և ենթադրաբար ինչ-որ բան կարդում ենք դրանում: Փաստորեն, PostgreSQL-ը «խելացի» է և ուղղակիորեն այնտեղ ոչինչ չի կարդա: Այնուհետև մենք վերցնում ենք նրանից առաջին ձայնագրությունը, իսկ հարյուր և առաջինը նույն CTE-ից:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Մենք նայում ենք պլանին և հասկանում. տարօրինակ է, մենք ունենք 3 բուֆեր (տվյալների էջեր) «սպառված» Seq Scan-ում, ևս 1-ը CTE Scan-ում և ևս 2-ը երկրորդ CTE Scan-ում: Այսինքն, եթե մենք պարզապես ամփոփենք ամեն ինչ, մենք կստանանք 6, բայց պլանշետից մենք կարդում ենք միայն 3: CTE Scan-ը ոչ մի տեղից ոչինչ չի կարդում, այլ ուղղակիորեն աշխատում է գործընթացի հիշողության հետ: Այսինքն, այստեղ ինչ-որ բան ակնհայտորեն սխալ է:

Փաստորեն, պարզվում է, որ այստեղ են բոլոր այն 3 էջերը, որոնք պահանջվել են Seq Scan-ից, սկզբում 1-ը խնդրել է 1-ին CTE Scan-ը, իսկ հետո 2-րդը և ևս 2-ը կարդացվել է նրան, այսինքն՝ ընդհանուր Կարդացվել է 3 էջ, ոչ թե 6:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Եվ այս նկարը մեզ հանգեցրեց այն ըմբռնմանը, որ պլանի կատարումն այլևս ծառ չէ, այլ պարզապես ինչ-որ ացիկլիկ գրաֆիկ: Եվ մենք ստացանք այսպիսի գծապատկեր, որպեսզի հասկանանք, թե «ինչը որտեղից առաջին հերթին եկավ»: Այսինքն, այստեղ մենք pg_class-ից ստեղծեցինք CTE, և երկու անգամ խնդրեցինք, և գրեթե ամբողջ ժամանակը ծախսվեց մասնաճյուղի վրա, երբ 2-րդ անգամ խնդրեցինք: Հասկանալի է, որ 101-րդ գրառումը կարդալը շատ ավելի թանկ է, քան պարզապես պլանշետից 1-ին գրառումը կարդալը:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Մի քիչ արտաշնչեցինք։ Նրանք ասացին. «Հիմա, Նեո, դու գիտես քունգ ֆու: Այժմ մեր փորձը հենց ձեր էկրանին է: Այժմ դուք կարող եք օգտագործել այն»: [հոդված]

Մատյանների համախմբում

Մեր 1000 մշակողները թեթեւացած շունչ քաշեցին։ Բայց մենք հասկացանք, որ ունենք ընդամենը հարյուրավոր «մարտական» սերվերներ, և ծրագրավորողների կողմից այս ամբողջ «copy-paste»-ը բոլորովին հարմար չէ։ Մենք հասկացանք, որ պետք է ինքներս հավաքենք։

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Ընդհանուր առմամբ, կա ստանդարտ մոդուլ, որը կարող է վիճակագրություն հավաքել, այնուամենայնիվ, այն նաև պետք է ակտիվացվի կազմաձևում. մոդուլ pg_stat_statements. Բայց նա մեզ չէր համապատասխանում:

Նախ, այն վերագրում է նույն հարցումներին՝ օգտագործելով տարբեր սխեմաներ նույն տվյալների բազայում տարբեր QueryIds. Այսինքն, եթե առաջին հերթին անեք SET search_path = '01'; SELECT * FROM user LIMIT 1;եւ հետո SET search_path = '02'; և նույն հարցումը, ապա այս մոդուլի վիճակագրությունը կունենա տարբեր գրառումներ, և ես չեմ կարողանա ընդհանուր վիճակագրություն հավաքել հատուկ այս հարցման պրոֆիլի համատեքստում, առանց հաշվի առնելու սխեմաները:

Երկրորդ կետը, որը մեզ խանգարեց օգտագործել այն պլանների բացակայություն. Այսինքն՝ ծրագիր չկա, կա միայն բուն խնդրանքը։ Մենք տեսնում ենք, թե ինչն էր դանդաղում, բայց չենք հասկանում, թե ինչու։ Եվ այստեղ մենք վերադառնում ենք արագ փոփոխվող տվյալների բազայի խնդրին:

Եվ վերջին պահը - «փաստերի» բացակայություն. Այսինքն, դուք չեք կարող անդրադառնալ հարցման կատարման կոնկրետ օրինակին. չկա, կա միայն ագրեգացված վիճակագրություն: Թեև սրա հետ հնարավոր է աշխատել, պարզապես շատ դժվար է։

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Ուստի որոշեցինք պայքարել copy-paste-ի դեմ ու սկսեցինք գրել կոլեկցիոներ.

Կոլեկցիոները միանում է SSH-ի միջոցով, սերվերի հետ անվտանգ կապ է հաստատում տվյալների բազայի հետ՝ օգտագործելով վկայագիր և tail -F «կառչում» է դրան լոգ ֆայլում: Այսպիսով, այս նիստում մենք ստանում ենք ամբողջ լոգ ֆայլի ամբողջական «հայելին»:, որը ստեղծում է սերվերը: Սերվերի բեռը ինքնին նվազագույն է, քանի որ մենք այնտեղ ոչինչ չենք վերլուծում, մենք պարզապես արտացոլում ենք տրաֆիկը:

Քանի որ մենք արդեն սկսել էինք գրել ինտերֆեյսը Node.js-ում, մենք շարունակեցինք դրա մեջ գրել կոլեկցիոները։ Եվ այս տեխնոլոգիան արդարացրել է իրեն, քանի որ շատ հարմար է JavaScript-ի միջոցով աշխատել թույլ ֆորմատավորված տեքստային տվյալների հետ, որը հենց տեղեկամատյանն է։ Իսկ Node.js ենթակառուցվածքն ինքնին որպես հետին պլանի հարթակ թույլ է տալիս հեշտությամբ և հարմարավետ աշխատել ցանցային կապերի և իսկապես ցանկացած տվյալների հոսքերի հետ:

Համապատասխանաբար, մենք «ձգում» ենք երկու կապ՝ առաջինը՝ «լսելու» գերանը ինքնին և տանում այն ​​մեզ մոտ, իսկ երկրորդը՝ պարբերաբար հարցնելու բազայից: «Բայց գրանցամատյանը ցույց է տալիս, որ oid 123 նշանն արգելափակված է», բայց դա ոչինչ չի նշանակում մշակողի համար, և լավ կլիներ հարցնել տվյալների բազային. «Ի՞նչ է OID = 123, այնուամենայնիվ»: Եվ այսպես, մենք պարբերաբար հարցնում ենք բազային այն, ինչ մենք դեռ չգիտենք մեր մասին:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

«Միայն մի բան կա, որ դուք հաշվի չեք առել, կա փղի նման մեղուների մի տեսակ»: Մենք սկսեցինք զարգացնել այս համակարգը, երբ ցանկանում էինք վերահսկել 10 սերվեր: Ամենակարևորը մեր հասկացողությամբ, որտեղ առաջացան որոշ խնդիրներ, որոնց հետ դժվար էր հաղթահարել: Բայց առաջին եռամսյակում մենք հարյուրը ստացանք մոնիտորինգի համար, քանի որ համակարգը աշխատում էր, բոլորն էին ուզում, բոլորը հարմար էին:

Այս ամենը պետք է գումարել, տվյալների հոսքը մեծ է և ակտիվ: Իրականում այն, ինչ մենք վերահսկում ենք, ինչի հետ կարող ենք գործ ունենալ, դա այն է, ինչ մենք օգտագործում ենք: Մենք նաև օգտագործում ենք PostgreSQL որպես տվյալների պահեստ: Եվ ոչինչ ավելի արագ չէ դրա մեջ տվյալներ «լցնելու», քան օպերատորը COPY Դեռ ոչ.

Սակայն տվյալների պարզապես «լցնելը» իրականում մեր տեխնոլոգիան չէ: Որովհետև, եթե հարյուր սերվերի վրա վայրկյանում ունեք մոտավորապես 50 հազար հարցում, ապա դա կստեղծի օրական 100-150 ԳԲ տեղեկամատյաններ: Հետևաբար, մենք պետք է խնամքով «կտրեինք» հիմքը։

Նախ, մենք արեցինք բաժանում ըստ օրվա, քանի որ օրերի հարաբերակցությունը մեծ հաշվով ոչ մեկին չի հետաքրքրում։ Ի՞նչ տարբերություն, թե ինչ ունեիք երեկ, եթե այսօր երեկոյան դուք թողարկեք հավելվածի նոր տարբերակը, և արդեն որոշ նոր վիճակագրություն:

Երկրորդ, մենք սովորեցինք (ստիպված էինք) շատ, շատ արագ գրել օգտագործելով COPY. Այսինքն՝ ոչ միայն COPYքանի որ նա ավելի արագ է, քան INSERT, և նույնիսկ ավելի արագ:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Երրորդ կետը՝ ես ստիպված էի հրաժարվել ձգաններից, համապատասխանաբար, և արտաքին բանալիներից. Այսինքն՝ մենք ընդհանրապես չունենք ռեֆերենցիոն ամբողջականություն։ Որովհետև եթե դուք ունեք աղյուսակ, որն ունի զույգ FK-ներ, և տվյալների բազայի կառուցվածքում ասում եք, որ «այստեղ կա գրանցամատյան, որը հղում է կատարում FK-ի կողմից, օրինակ, գրառումների խմբին», ապա երբ այն տեղադրեք, PostgreSQL նրան ոչինչ չի մնում, քան այն, թե ինչպես դա վերցնել և ազնվորեն անել SELECT 1 FROM master_fk1_table WHERE ... նույնացուցիչով, որը դուք փորձում եք տեղադրել, պարզապես ստուգելու համար, որ այս գրառումն առկա է այնտեղ, որ դուք չեք «կոտրել» այս Արտաքին բանալին ձեր ներդրմամբ:

Թիրախային աղյուսակի և դրա ինդեքսների մեկ գրառումի փոխարեն մենք ստանում ենք լրացուցիչ առավելություն՝ կարդալու բոլոր աղյուսակները, որոնց նա վերաբերում է: Բայց դա մեզ ամենևին պետք չէ. մեր խնդիրն է հնարավորինս շատ և հնարավորինս արագ ձայնագրել նվազագույն ծանրաբեռնվածությամբ: Այնպես որ, FK - ներքեւ!

Հաջորդ կետը համախմբումն ու հաշինգն է: Սկզբում մենք դրանք ներդրեցինք տվյալների բազայում, ի վերջո, հարմար է անմիջապես, երբ գրառում է գալիս, դա անել ինչ-որ պլանշետով «գումարած մեկ» հենց ձգանի մեջ. Դե, դա հարմար է, բայց նույն վատ բանը. դու տեղադրում ես մեկ գրառում, բայց ստիպված ես մեկ այլ աղյուսակից կարդալ և գրել այլ բան: Ընդ որում, ոչ միայն գրում ու կարդում ես, այլև դա անում ես ամեն անգամ։

Այժմ պատկերացրեք, որ դուք ունեք աղյուսակ, որտեղ դուք պարզապես հաշվում եք կոնկրետ հոսթի միջոցով անցած հարցումների քանակը. +1, +1, +1, ..., +1. Եվ դուք, սկզբունքորեն, դրա կարիքը չունեք, ամեն ինչ հնարավոր է հիշողության գումար կոլեկցիոների վրա և մեկ քայլով ուղարկեք տվյալների բազա +10.

Այո, որոշ խնդիրների դեպքում ձեր տրամաբանական ամբողջականությունը կարող է «փլուզվել», բայց սա գրեթե անիրատեսական դեպք է, քանի որ դուք ունեք նորմալ սերվեր, այն ունի մարտկոց վերահսկիչում, դուք ունեք գործարքների գրանցամատյան, գրանցամատյան: ֆայլային համակարգ... Ընդհանրապես, դա չարժե: Արտադրողականության կորուստը, որը դուք ստանում եք գործարկվող գործարկիչներից/FK-ից, չարժե ձեր կատարած ծախսերին:

Նույնն է հեշինգի դեպքում։ Որոշակի հարցումը թռչում է քեզ մոտ, դու տվյալների բազայում դրանից հաշվում ես որոշակի իդենտիֆիկատոր, գրում ես տվյալների բազայում և հետո բոլորին ասում: Ամեն ինչ լավ է, քանի դեռ ձայնագրման պահին ձեզ մոտ չի գա երկրորդ մարդ, ով ցանկանում է ձայնագրել նույնը, և դուք արգելափակվում եք, և սա արդեն վատ է: Հետևաբար, եթե դուք կարող եք փոխանցել որոշ ID-ների սերունդը հաճախորդին (համեմատած տվյալների բազայի հետ), ավելի լավ է դա անել:

Պարզապես մեզ համար կատարյալ էր տեքստից օգտագործել MD5-ը` հարցում, պլան, կաղապար,... Մենք այն հաշվարկում ենք հավաքողի կողմից, իսկ պատրաստի ID-ն «լցնում» տվյալների բազա: MD5-ի երկարությունը և ամենօրյա բաժանումը թույլ են տալիս չանհանգստանալ հնարավոր բախումներից:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Բայց այս ամենը արագ ձայնագրելու համար մեզ անհրաժեշտ էր փոփոխել ձայնագրման կարգը։

Ինչպե՞ս եք սովորաբար գրում տվյալներ: Մենք ունենք մի տեսակ տվյալների բազա, մենք այն բաժանում ենք մի քանի աղյուսակների, և այնուհետև ԿՈՊԻՐՈՒՄ ենք այն՝ սկզբում առաջինի, հետո երկրորդի մեջ, երրորդի մեջ... Դա անհարմար է, քանի որ մենք կարծես թե գրում ենք տվյալների մեկ հոսք երեք քայլով։ հաջորդաբար. Տհաճ. Կարո՞ղ է դա ավելի արագ անել: Կարող է

Դա անելու համար բավական է պարզապես այս հոսքերը միմյանց զուգահեռ քայքայել։ Ստացվում է, որ մենք ունենք սխալներ, հարցումներ, կաղապարներ, արգելափակումներ, ... թռչում են առանձին թելերով, և մենք այդ ամենը գրում ենք զուգահեռ: Բավական է սրա համար Պահպանեք COPY ալիքը մշտապես բաց յուրաքանչյուր առանձին թիրախային աղյուսակի համար.

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Այսինքն՝ կոլեկցիոների մոտ միշտ հոսք կա, որի մեջ կարող եմ գրել ինձ անհրաժեշտ տվյալները: Բայց որպեսզի տվյալների բազան տեսնի այս տվյալները, և ինչ-որ մեկը չխրվի սպասելով այս տվյալների գրմանը, COPY-ը պետք է ընդհատվի որոշակի պարբերականությամբ. Մեզ համար ամենաարդյունավետ ժամանակահատվածը մոտ 100 մս էր. մենք փակում ենք այն և անմիջապես բացում այն ​​նույն սեղանի վրա: Եվ եթե որոշ գագաթների ժամանակ մեզ չի բավականացնում մեկ հոսքը, ապա մենք կատարում ենք միավորում մինչև որոշակի սահման:

Բացի այդ, մենք պարզեցինք, որ նման բեռնվածության պրոֆիլի համար ցանկացած ագրեգացիա, երբ գրառումները հավաքվում են խմբաքանակով, չարիք է: Դասական չարությունն է INSERT ... VALUES և հետագա 1000 գրառում: Քանի որ այդ պահին դուք ունեք գրելու գագաթնակետ մեդիայի վրա, և բոլոր մյուսները, ովքեր փորձում են ինչ-որ բան գրել սկավառակի վրա, կսպասեն:

Նման անոմալիաներից ազատվելու համար պարզապես ոչինչ մի համախմբեք, ընդհանրապես մի բուֆերացրեք. Եվ եթե սկավառակի վրա բուֆերավորումն իսկապես տեղի է ունենում (բարեբախտաբար, Node.js-ի Stream API-ն թույլ է տալիս պարզել) - հետաձգեք այս կապը: Երբ դուք ստանում եք միջոցառում, որ այն կրկին անվճար է, գրեք դրան կուտակված հերթից։ Եվ քանի դեռ այն զբաղված է, վերցրեք հաջորդ անվճարը լողավազանից և գրեք դրան:

Նախքան տվյալների ձայնագրման այս մոտեցումը ներկայացնելը, մենք ունեինք մոտավորապես 4K գրելու օպերացիաներ, և այս կերպ մենք կրճատեցինք բեռը 4 անգամ: Այժմ դրանք աճել են ևս 6 անգամ՝ նոր վերահսկվող տվյալների բազաների շնորհիվ՝ մինչև 100 ՄԲ/վ: Եվ հիմա մենք պահում ենք վերջին 3 ամսվա տեղեկամատյանները մոտ 10-15 ՏԲ ծավալով՝ հուսալով, որ ընդամենը երեք ամսում ցանկացած ծրագրավորող կկարողանա լուծել ցանկացած խնդիր։

Մենք հասկանում ենք խնդիրները

Բայց պարզապես այս բոլոր տվյալները հավաքելը լավ է, օգտակար, տեղին, բայց ոչ բավարար, դա պետք է հասկանալ: Քանի որ դրանք օրական միլիոնավոր տարբեր ծրագրեր են:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Բայց միլիոններն անկառավարելի են, նախ պետք է «փոքր» անել։ Եվ, առաջին հերթին, պետք է որոշել, թե ինչպես եք կազմակերպելու այս «ավելի փոքր» իրը։

Մենք առանձնացրել ենք երեք հիմնական կետ.

  • ով ուղարկել է այս հարցումը
    Այսինքն՝ ո՞ր հավելվածից է այն «հասել»՝ վեբ ինտերֆեյս, բեքենդ, վճարային համակարգ, թե այլ բան։
  • որտեղ դա տեղի է ունեցել
    Ո՞ր կոնկրետ սերվերի վրա: Որովհետև, եթե մեկ հավելվածի տակ ունեք մի քանի սերվեր, և հանկարծ մեկը «հիմար է դառնում» (քանի որ «սկավառակը փտած է», «հիշողության արտահոսք», ինչ-որ այլ խնդիր), ապա դուք պետք է հատուկ դիմեք սերվերին:
  • ինչպես խնդիրն այս կամ այն ​​կերպ դրսևորվեց

Հասկանալու համար, թե «ով» է մեզ հարցում ուղարկել, մենք օգտագործում ենք ստանդարտ գործիք՝ սահմանելով նստաշրջանի փոփոխական. SET application_name = '{bl-host}:{bl-method}'; — մենք ուղարկում ենք բիզնես տրամաբանության հոսթի անունը, որից ստացվում է հարցումը, և մեթոդի կամ հավելվածի անվանումը, որը նախաձեռնել է այն:

Հարցման «սեփականատիրոջը» անցնելուց հետո այն պետք է դուրս բերվի տեղեկամատյան, դրա համար մենք կարգավորում ենք փոփոխականը log_line_prefix = ' %m [%p:%v] [%d] %r %a'. Հետաքրքրվողների համար, գուցե նայեք ձեռնարկումինչ է նշանակում այդ ամենը: Պարզվում է, որ գրանցամատյանում տեսնում ենք.

  • ժամանակ
  • գործընթացի և գործարքի նույնացուցիչները
  • տվյալների բազայի անվանումը
  • Այս հարցումն ուղարկած անձի IP-ն
  • և մեթոդի անվանումը

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Հետո մենք հասկացանք, որ այնքան էլ հետաքրքիր չէ տարբեր սերվերների միջև մեկ հարցման հարաբերակցությանը նայելը: Հաճախ չէ, որ դուք ունենում եք մի իրավիճակ, երբ մեկ հավելվածը հավասարապես պտտվում է այստեղ և այնտեղ: Բայց նույնիսկ եթե դա նույնն է, նայեք այս սերվերներից որևէ մեկին.

Այսպիսով, ահա կտրվածքը «մեկ սերվեր՝ մեկ օր» դա մեզ բավական է ցանկացած վերլուծության համար։

Առաջին վերլուծական բաժինը նույնն է «նմուշ» - պլանի ներկայացման կրճատ ձև, որը մաքրված է բոլոր թվային ցուցանիշներից: Երկրորդ կտրվածքը հավելվածն է կամ մեթոդը, իսկ երրորդ կտրվածքը կոնկրետ պլանի հանգույցն է, որը մեզ խնդիրներ է առաջացրել:

Երբ մենք կոնկրետ օրինակներից տեղափոխվեցինք կաղապարներ, մենք միանգամից երկու առավելություն ստացանք.

  • վերլուծության համար նախատեսված օբյեկտների քանակի բազմակի կրճատում
    Մենք խնդիրն այլևս պետք է վերլուծենք ոչ թե հազարավոր հարցումներով կամ պլաններով, այլ տասնյակ ձևանմուշներով։
  • ժամանակացույցը
    Այսինքն՝ որոշակի հատվածում «փաստերն» ամփոփելով՝ կարող ես օրվա ընթացքում ցուցադրել դրանց տեսքը։ Եվ այստեղ դուք կարող եք հասկանալ, որ եթե դուք ունեք ինչ-որ օրինաչափություն, որը տեղի է ունենում, օրինակ, ժամը մեկ անգամ, բայց դա պետք է տեղի ունենա օրը մեկ անգամ, դուք պետք է մտածեք, թե ինչն է սխալ եղել. չպետք է: Սա վերլուծության ևս մեկ ոչ թվային, զուտ տեսողական մեթոդ է։

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Մնացած մեթոդները հիմնված են այն ցուցանիշների վրա, որոնք մենք հանում ենք պլանից՝ քանի անգամ է նման օրինաչափություն տեղի ունեցել, ընդհանուր և միջին ժամանակը, որքան տվյալներ են կարդացվել սկավառակից և որքանը՝ հիշողությունից...

Քանի որ, օրինակ, դուք գալիս եք հաղորդավարի վերլուծական էջ, նայեք, ինչ-որ բան սկսում է շատ կարդալ սկավառակի վրա: Սերվերի սկավառակը չի կարող կարգավորել այն. ո՞վ է կարդում դրանից:

Եվ դուք կարող եք տեսակավորել ըստ ցանկացած սյունակի և որոշել, թե ինչի հետ գործ կունենաք հենց հիմա՝ պրոցեսորի կամ սկավառակի ծանրաբեռնվածությունը, թե ընդհանուր հարցումների քանակը... Մենք այն տեսակավորեցինք, նայեցինք «վերևները», ուղղեցինք և ներկայացրել է հավելվածի նոր տարբերակը:
[վիդեո դասախոսություն]

Եվ անմիջապես դուք կարող եք տեսնել տարբեր հավելվածներ, որոնք գալիս են նույն ձևանմուշով նման հարցումից SELECT * FROM users WHERE login = 'Vasya'. Frontend, backend, processing... Եվ դուք զարմանում եք, թե ինչու պրոցեսինգը կկարդա օգտատիրոջը, եթե նա իր հետ չի շփվում։

Հակառակ ճանապարհը հավելվածից անմիջապես տեսնելն է, թե ինչ է անում: Օրինակ, ֆրոնտենդը սա է, սա, սա և սա ժամը մեկ անգամ (ժամանակացույցն օգնում է): Եվ անմիջապես հարց է ծագում՝ թվում է, թե ֆրոնտենդի գործը չէ ժամը մեկ անգամ ինչ-որ բան անելը...

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Որոշ ժամանակ անց մենք հասկացանք, որ մեզ պակասում է ագրեգատը վիճակագրություն ըստ պլանի հանգույցների. Մենք պլաններից առանձնացրել ենք միայն այն հանգույցները, որոնք իրենք ինչ-որ բան են անում աղյուսակների տվյալների հետ (կարդում/գրում են դրանք ըստ ինդեքսների, թե ոչ): Փաստորեն, նախորդ նկարի համեմատ ավելացված է միայն մեկ կողմ. քանի ռեկորդ է բերել մեզ այս հանգույցը:, և քանիսն են անտեսվել (Տողերը հեռացվել են զտիչով):

Դուք չունեք համապատասխան ինդեքս ափսեի վրա, դուք հարցում եք անում դրան, այն անցնում է ինդեքսից, ընկնում է Seq Scan... դուք զտել եք բոլոր գրառումները, բացի մեկից: Ինչու՞ են ձեզ հարկավոր օրական 100 միլիոն ֆիլտրացված գրառումներ: Ավելի լավ չէ՞ ինդեքսը հավաքել:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Վերլուծելով բոլոր պլանները հանգույց առ հանգույց՝ մենք հասկացանք, որ պլաններում կան որոշ բնորոշ կառուցվածքներ, որոնք, ամենայն հավանականությամբ, կասկածելի տեսք կունենան: Եվ լավ կլինի ծրագրավորողին ասել. «Ընկեր, այստեղ նախ կարդում ես ըստ ինդեքսների, հետո տեսակավորում, հետո կտրում», - որպես կանոն, կա մեկ գրառում:

Բոլորը, ովքեր հարցումներ են գրել, հավանաբար հանդիպել են այս օրինաչափությանը. «Տվեք ինձ Վասյաի վերջին պատվերը, դրա ամսաթիվը»: Եվ եթե դուք չունեք ինդեքս ըստ ամսաթվի, կամ ձեր օգտագործած ինդեքսում ամսաթիվ չկա, ապա դուք ոտք դրեք նույն «փոցխի» վրա:

Բայց մենք գիտենք, որ սա «փոցխ» է, ուստի ինչու անմիջապես չասել մշակողին, թե ինչ պետք է անի: Համապատասխանաբար, հիմա պլան բացելիս մեր ծրագրավորողը անմիջապես տեսնում է մի գեղեցիկ նկար՝ հուշումներով, որտեղ նրան անմիջապես ասում են.

Արդյունքում, փորձի այն քանակությունը, որն անհրաժեշտ էր սկզբում և այժմ, զգալիորեն նվազել է։ Սա այն տեսակի գործիքն է, որը մենք ունենք:

PostgreSQL հարցումների զանգվածային օպտիմիզացում: Կիրիլ Բորովիկով (Տենսոր)

Source: www.habr.com

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