Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Հոդվածում ես ձեզ կպատմեմ, թե ինչպես ենք մենք մոտեցել PostgreSQL սխալների հանդուրժողականության հարցին, ինչու է այն կարևոր դարձել մեզ համար և ինչ եղավ վերջում։

Մենք ունենք բարձր բեռնված ծառայություն՝ 2,5 միլիոն օգտատեր ամբողջ աշխարհում, 50 հազար+ ակտիվ օգտատեր ամեն օր: Սերվերները գտնվում են Amazone-ում՝ Իռլանդիայի մեկ տարածաշրջանում. 100+ տարբեր սերվերներ անընդհատ աշխատում են, որոնցից գրեթե 50-ը տվյալների բազաներով են։

Ամբողջ հետնամասը մեծ մոնոլիտ պետական ​​Java հավելված է, որը մշտական ​​վեբսոկետ կապ է պահպանում հաճախորդի հետ: Երբ մի քանի օգտատերեր աշխատում են միևնույն տախտակի վրա, նրանք բոլորը տեսնում են փոփոխությունները իրական ժամանակում, քանի որ մենք յուրաքանչյուր փոփոխություն գրում ենք տվյալների բազայում: Մենք վայրկյանում մոտ 10 հազար հարցում ունենք մեր տվյալների բազաներին: Redis-ում առավելագույն բեռնվածության դեպքում մենք վայրկյանում գրում ենք 80-100K հարցում:
Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Ինչու մենք Redis-ից անցանք PostgreSQL

Սկզբում մեր ծառայությունն աշխատում էր Redis-ի հետ՝ առանցքային արժեքների խանութ, որը պահում է բոլոր տվյալները սերվերի RAM-ում:

Redis-ի առավելությունները.

  1. Բարձր արձագանքման արագություն, քանի որ ամեն ինչ պահվում է հիշողության մեջ;
  2. Կրկնօրինակման և կրկնօրինակման հեշտությունը:

Redis-ի թերությունները մեզ համար.

  1. Իրական գործարքներ չկան։ Մենք փորձեցինք դրանք մոդելավորել մեր հավելվածի մակարդակով։ Ցավոք սրտի, դա միշտ չէ, որ լավ էր աշխատում և պահանջում էր գրել շատ բարդ կոդ:
  2. Տվյալների քանակը սահմանափակվում է հիշողության քանակով: Քանի որ տվյալների քանակը մեծանում է, հիշողությունը կաճի, և, ի վերջո, մենք կբախվենք ընտրված օրինակի բնութագրերին, ինչը AWS-ում պահանջում է դադարեցնել մեր ծառայությունը՝ օրինակի տեսակը փոխելու համար:
  3. Անհրաժեշտ է մշտապես պահպանել հետաձգման ցածր մակարդակ, քանի որ. մենք ունենք շատ մեծ թվով հարցումներ։ Մեզ համար ուշացման օպտիմալ մակարդակը 17-20 մվ է: 30-40 ms մակարդակում մենք երկար պատասխաններ ենք ստանում մեր դիմումից և ծառայության դեգրադացիայից ստացված հարցումներին: Ցավոք, դա մեզ հետ պատահեց 2018 թվականի սեպտեմբերին, երբ Redis-ի հետ կապված դեպքերից մեկը ինչ-ինչ պատճառներով սովորականից 2 անգամ ավելի ուշացում ստացավ: Խնդիրը լուծելու համար մենք կեսօր դադարեցրինք ծառայությունը չպլանավորված սպասարկման պատճառով և փոխարինեցինք Redis-ի խնդրահարույց օրինակը:
  4. Հեշտ է ստանալ տվյալների անհամապատասխանություն նույնիսկ կոդում աննշան սխալների դեպքում, այնուհետև շատ ժամանակ ծախսել կոդ գրելով՝ այս տվյալները շտկելու համար:

Մենք հաշվի առանք բացասական կողմերը և հասկացանք, որ պետք է ավելի հարմար բանի անցնել՝ նորմալ գործարքներով և ուշացումից ավելի քիչ կախվածությամբ։ Իրականացրել է հետազոտություն, վերլուծել բազմաթիվ տարբերակներ և ընտրել PostgreSQL-ը:

Մենք արդեն 1,5 տարի է, ինչ տեղափոխվել ենք նոր տվյալների բազա և տեղափոխել ենք տվյալների միայն մի փոքր մասը, ուստի այժմ մենք աշխատում ենք Redis-ի և PostgreSQL-ի հետ միաժամանակ։ Տվյալների տվյալների շտեմարանների միջև տեղափոխման և փոխարկման փուլերի մասին լրացուցիչ տեղեկություններ գրված են իմ գործընկերոջ հոդվածը.

Երբ մենք առաջին անգամ սկսեցինք շարժվել, մեր հավելվածն անմիջապես աշխատում էր տվյալների բազայի հետ և մուտք գործեց վարպետ Redis և PostgreSQL: PostgreSQL կլաստերը բաղկացած էր հիմնականից և ասինխրոն կրկնօրինակմամբ կրկնօրինակից: Ահա թե ինչ տեսք ուներ տվյալների բազայի սխեման.
Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

PgBouncer-ի իրականացում

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

Կապի մենեջերի համար մենք ունեինք երկու տարբերակ՝ Pgpool և PgBouncer: Բայց առաջինը չի աջակցում տվյալների բազայի հետ աշխատելու գործարքային ռեժիմին, ուստի մենք ընտրեցինք PgBouncer-ը:

Մենք ստեղծել ենք աշխատանքի հետևյալ սխեման. մեր հավելվածը մուտք է գործում մեկ PgBouncer, որի հետևում PostgreSQL վարպետներն են, և յուրաքանչյուր վարպետի հետևում կա մեկ կրկնօրինակ՝ ասինխրոն կրկնօրինակմամբ։
Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

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

PgBouncer-ի ձախողում

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

Դրանից հետո մենք լրջորեն մտածեցինք PgBouncer և PostgreSQL կլաստերների սխալների հանդուրժողականության մասին, քանի որ նմանատիպ իրավիճակ կարող է պատահել մեր AWS հաշվի ցանկացած օրինակի հետ:

Մենք կառուցեցինք PgBouncer սխալների հանդուրժողականության սխեման հետևյալ կերպ. հավելվածի բոլոր սերվերները մուտք են գործում ցանցի բեռնման հավասարակշռող սարք, որի հետևում կա երկու PgBouncer: Յուրաքանչյուր PgBouncer նայում է յուրաքանչյուր բեկորի նույն PostgreSQL վարպետին: Եթե ​​AWS-ի օրինակի խափանումը նորից տեղի ունենա, ամբողջ երթևեկությունը վերահղվում է մեկ այլ PgBouncer-ի միջոցով: Network Load Balancer-ի ձախողումը տրամադրվում է AWS-ի կողմից:

Այս սխեման հեշտացնում է նոր PgBouncer սերվերների ավելացումը:
Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Ստեղծեք PostgreSQL Failover Cluster

Այս խնդիրը լուծելիս մենք դիտարկել ենք տարբեր տարբերակներ՝ ինքնուրույն գրված failover, repmgr, AWS RDS, Patroni:

Ինքնուրույն գրված սցենարներ

Նրանք կարող են վերահսկել վարպետի աշխատանքը և, եթե այն ձախողվի, խթանել կրկնօրինակը վարպետին և թարմացնել PgBouncer-ի կոնֆիգուրացիան:

Այս մոտեցման առավելությունները առավելագույն պարզությունն են, քանի որ դուք ինքներդ գրում եք սցենարներ և հստակ հասկանում եք, թե ինչպես են դրանք աշխատում:

Դեմ:

  • Վարպետը կարող էր չմեռնել, փոխարենը կարող էր ցանցի խափանում լինել: Failover-ը, դա անտեղյակ լինելով, կխթանի կրկնօրինակը վարպետին, մինչդեռ հին վարպետը կշարունակի աշխատել: Արդյունքում մենք կստանանք երկու սերվեր՝ վարպետի դերում, և չենք իմանա, թե դրանցից որն ունի ամենաթարմ տվյալները։ Այս իրավիճակը կոչվում է նաև պառակտված ուղեղ;
  • Մենք մնացինք առանց արձագանքի։ Մեր կոնֆիգուրացիայից՝ հիմնականը և մեկ կրկնօրինակը, փոխարկումից հետո կրկնօրինակը տեղափոխվում է վերև դեպի հիմնական, և մենք այլևս չունենք կրկնօրինակներ, ուստի մենք պետք է ձեռքով ավելացնենք նոր կրկնօրինակ։
  • Մեզ անհրաժեշտ է ձախողման գործողության լրացուցիչ մոնիտորինգ, մինչդեռ մենք ունենք 12 PostgreSQL բեկորներ, ինչը նշանակում է, որ մենք պետք է վերահսկենք 12 կլաստեր: Բեկորների քանակի ավելացմամբ դուք պետք է նաև հիշեք թարմացնել ֆայլովերը:

Ինքնագրված failover-ը շատ բարդ տեսք ունի և պահանջում է ոչ աննշան աջակցություն: Մեկ PostgreSQL կլաստերի դեպքում սա կլինի ամենահեշտ տարբերակը, բայց այն չի չափվում, ուստի այն մեզ համար հարմար չէ:

Repmgr

Replication Manager PostgreSQL կլաստերների համար, որը կարող է կառավարել PostgreSQL կլաստերի աշխատանքը: Միևնույն ժամանակ, այն տուփից դուրս ավտոմատ ձախողում չունի, ուստի աշխատանքի համար ձեզ հարկավոր է պատրաստի լուծույթի վերևում գրել ձեր սեփական «փաթաթան»: Այսպիսով, ամեն ինչ կարող է նույնիսկ ավելի բարդ լինել, քան ինքնուրույն գրված սցենարները, այնպես որ մենք նույնիսկ չփորձեցինք Repmgr-ը:

AWS RDS

Աջակցում է այն ամենին, ինչ մեզ անհրաժեշտ է, գիտի, թե ինչպես կատարել կրկնօրինակումներ և պահպանում է կապերի լողավազան: Այն ունի ավտոմատ միացում. երբ վարպետը մահանում է, կրկնօրինակը դառնում է նոր վարպետ, և AWS-ը փոխում է dns գրառումը նոր վարպետի, մինչդեռ կրկնօրինակները կարող են տեղակայվել տարբեր AZ-ներում:

Թերությունները ներառում են նուրբ ճշգրտումների բացակայությունը: Որպես նուրբ թյունինգի օրինակ․ մեր օրինակները սահմանափակումներ ունեն tcp կապերի համար, ինչը, ցավոք, հնարավոր չէ անել RDS-ում.

net.ipv4.tcp_keepalive_time=10
net.ipv4.tcp_keepalive_intvl=1
net.ipv4.tcp_keepalive_probes=5
net.ipv4.tcp_retries2=3

Բացի այդ, AWS RDS-ը գրեթե երկու անգամ ավելի թանկ է, քան սովորական օրինակի գինը, ինչը այս լուծումից հրաժարվելու հիմնական պատճառն էր:

Հովանավոր

Սա python ձևանմուշ է՝ PostgreSQL-ը կառավարելու համար՝ լավ փաստաթղթերով, ավտոմատ ձախողմամբ և ելակետային կոդով github-ում:

Patroni-ի առավելությունները.

  • Յուրաքանչյուր կոնֆիգուրացիայի պարամետր նկարագրված է, պարզ է, թե ինչպես է այն աշխատում.
  • Ավտոմատ ձախողումն աշխատում է տուփից դուրս;
  • Գրված է python-ով, և քանի որ մենք ինքներս շատ ենք գրում python-ով, մեզ համար ավելի հեշտ կլինի լուծել խնդիրները և, հնարավոր է, նույնիսկ օգնել նախագծի զարգացմանը.
  • Լիովին կառավարում է PostgreSQL-ը, թույլ է տալիս միանգամից փոխել կլաստերի բոլոր հանգույցների կոնֆիգուրացիան, և եթե նոր կոնֆիգուրացիան կիրառելու համար կլաստերը պետք է վերագործարկվի, ապա դա կարելի է նորից անել Patroni-ի միջոցով:

Դեմ:

  • Փաստաթղթերից պարզ չէ, թե ինչպես ճիշտ աշխատել PgBouncer-ի հետ: Թեև դժվար է դա մինուս անվանել, քանի որ Patroni-ի խնդիրն է կառավարել PostgreSQL-ը, և թե ինչպես կանցնեն Patroni-ի հետ կապերը, արդեն մեր խնդիրն է.
  • Patroni-ի մեծ ծավալներով իրագործման օրինակները քիչ են, մինչդեռ զրոյից իրագործման բազմաթիվ օրինակներ կան:

Արդյունքում, մենք ընտրեցինք Patroni-ն՝ ձախողման կլաստեր ստեղծելու համար:

Պատրոնի իրականացման գործընթաց

Մինչ Patroni-ն, մենք ունեինք 12 PostgreSQL բեկորներ՝ մեկ հիմնական և մեկ կրկնօրինակի կազմաձևում՝ ասինխրոն կրկնօրինակմամբ: Հավելվածի սերվերները մուտք էին գործում տվյալների բազաներ Network Load Balancer-ի միջոցով, որի հետևում գտնվում էին երկու օրինակներ PgBouncer-ով, իսկ դրանց հետևում բոլոր PostgreSQL սերվերները:
Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Patroni-ն իրականացնելու համար մեզ անհրաժեշտ էր ընտրել բաշխված պահեստավորման կլաստերի կոնֆիգուրացիա: Patroni-ն աշխատում է բաշխված կոնֆիգուրացիայի պահպանման համակարգերով, ինչպիսիք են etcd, Zookeeper, Consul: Մենք պարզապես շուկայում ունենք լիարժեք հյուպատոսական կլաստեր, որն աշխատում է Vault-ի հետ համատեղ, և մենք այն այլևս չենք օգտագործում: Հիանալի պատճառ՝ սկսելու հյուպատոսն օգտագործել իր նպատակային նպատակների համար:

Ինչպես է Պատրոնին աշխատում հյուպատոսի հետ

Մենք ունենք Consul կլաստեր, որը բաղկացած է երեք հանգույցներից, և Patroni կլաստեր, որը բաղկացած է առաջնորդից և կրկնօրինակից (Պատրոնիում վարպետը կոչվում է կլաստերի առաջնորդ, իսկ ստրուկները՝ կրկնօրինակներ)։ Patroni կլաստերի յուրաքանչյուր ատյան անընդհատ տեղեկատվություն է ուղարկում կլաստերի վիճակի մասին հյուպատոսին: Հետևաբար, հյուպատոսից դուք միշտ կարող եք պարզել Patroni կլաստերի ներկայիս կազմաձևը և ով է տվյալ պահին առաջատարը:

Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

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

host: the host:port for the Consul endpoint, in format: http(s)://host:port
scheme: (optional) http or https, defaults to http

Դա պարզ է թվում, բայց այստեղ սկսվում են որոգայթները: Հյուպատոսի հետ մենք աշխատում ենք անվտանգ կապով https-ի միջոցով, և մեր կապի կազմաձևը կունենա հետևյալ տեսքը.

consul:
  host: https://server.production.consul:8080 
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

Բայց դա չի աշխատում: Գործարկման ժամանակ Patroni-ն չի կարող միանալ հյուպատոսին, քանի որ այն ամեն դեպքում փորձում է անցնել http-ով:

Պատրոնի սկզբնական կոդը օգնեց լուծել խնդիրը: Լավ է, որ գրված է python-ով։ Ստացվում է, որ հյուրընկալող պարամետրը ոչ մի կերպ չի վերլուծվում, և արձանագրությունը պետք է նշված լինի սխեմայով: Ահա թե ինչպես է մեզ համար հյուպատոսի հետ աշխատելու աշխատանքային կազմաձևման բլոկը.

consul:
  host: server.production.consul:8080
  scheme: https
  verify: true
  cacert: {{ consul_cacert }}
  cert: {{ consul_cert }}
  key: {{ consul_key }}

հյուպատոս-կաղապար

Այսպիսով, մենք ընտրել ենք պահեստը կազմաձևման համար: Այժմ մենք պետք է հասկանանք, թե ինչպես է PgBouncer-ը փոխելու իր կոնֆիգուրացիան Patroni կլաստերի առաջատարը փոխելիս: Փաստաթղթերում այս հարցի պատասխանը չկա, քանի որ. այնտեղ, սկզբունքորեն, PgBouncer-ի հետ աշխատանքը նկարագրված չէ:

Լուծում փնտրելով՝ գտանք հոդված (վերնագիրը, ցավոք, չեմ հիշում), որտեղ գրված էր, որ Сonsul-template-ը շատ է օգնել PgBouncer-ի և Patroni-ի զուգակցման հարցում։ Սա մեզ դրդեց հետաքննել, թե ինչպես է աշխատում Consul-template-ը:

Պարզվեց, որ Consul-template-ը մշտապես վերահսկում է Consul-ում PostgreSQL կլաստերի կազմաձևումը: Երբ առաջնորդը փոխվում է, այն թարմացնում է PgBouncer կոնֆիգուրացիան և հրաման է ուղարկում այն ​​վերաբեռնելու համար:

Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Կաղապարի մեծ պլյուսն այն է, որ այն պահվում է որպես կոդ, ուստի նոր բեկոր ավելացնելիս բավական է նոր commit կատարել և ինքնաբերաբար թարմացնել կաղապարը՝ աջակցելով Ենթակառուցվածքը որպես կոդ սկզբունքին։

Նոր ճարտարապետություն Պատրոնի հետ

Արդյունքում ստացանք աշխատանքի հետևյալ սխեման.
Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Բոլոր հավելվածների սերվերները մուտք են գործում հավասարակշռող → դրա հետևում կա PgBouncer-ի երկու օրինակ → յուրաքանչյուր օրինակում, գործարկվում է Consul-template, որը վերահսկում է յուրաքանչյուր Patroni կլաստերի կարգավիճակը և վերահսկում PgBouncer կոնֆիգուրայի համապատասխանությունը, որը հարցումներ է ուղարկում ներկայիս ղեկավարին: յուրաքանչյուր կլաստերի:

Ձեռքով փորձարկում

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

Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Կպչուն ետ վերադարձավ 10-20 վայրկյանի ընթացքում, իսկ հետո նորից սկսեց նորմալ շարժվել: Սա նշանակում է, որ Patroni կլաստերը ճիշտ է աշխատել՝ այն փոխել է առաջատարը, ուղարկել տեղեկատվությունը Сonsul-ին, իսկ Сonsul-template-ն անմիջապես վերցրել է այդ տեղեկատվությունը, փոխարինել PgBouncer-ի կոնֆիգուրացիան և ուղարկել վերաբեռնման հրամանը։

Ինչպե՞ս գոյատևել բարձր բեռի տակ և նվազագույնի հասցնել պարապուրդը:

Ամեն ինչ աշխատում է կատարյալ! Բայց կան նոր հարցեր. ինչպե՞ս է այն աշխատելու մեծ ծանրաբեռնվածության պայմաններում: Ինչպե՞ս արագ և ապահով կերպով դուրս բերել ամեն ինչ արտադրության մեջ:

Փորձարկման միջավայրը, որի վրա մենք իրականացնում ենք բեռնվածության փորձարկում, օգնում է մեզ պատասխանել առաջին հարցին: Այն ամբողջովին նույնական է արտադրությանը ճարտարապետական ​​առումով և ստեղծել է թեստային տվյալներ, որոնք ծավալով մոտավորապես հավասար են արտադրությանը: Մենք որոշում ենք պարզապես «սպանել» PostgreSQL վարպետներից մեկին թեստի ընթացքում և տեսնել, թե ինչ է տեղի ունենում: Բայց մինչ այդ կարևոր է ստուգել ավտոմատ գլորումը, քանի որ այս միջավայրում մենք ունենք մի քանի PostgreSQL բեկորներ, այնպես որ մենք կստանանք կազմաձևման սկրիպտների հիանալի փորձարկում մինչև արտադրությունը:

Երկու առաջադրանքներն էլ հավակնոտ տեսք ունեն, բայց մենք ունենք PostgreSQL 9.6: Կարո՞ղ ենք անմիջապես թարմացնել 11.2-ի:

Մենք որոշում ենք դա անել 2 քայլով. սկզբում թարմացրե՛ք մինչև 11.2, այնուհետև գործարկե՛ք Patroni:

PostgreSQL թարմացում

PostgreSQL տարբերակը արագ թարմացնելու համար օգտագործեք տարբերակը -k, որոնցում կոշտ հղումներ են ստեղծվում սկավառակի վրա և կարիք չկա պատճենելու ձեր տվյալները։ 300-400 ԳԲ բազայի վրա թարմացումը տևում է 1 վայրկյան:

Մենք ունենք շատ բեկորներ, ուստի թարմացումը պետք է կատարվի ավտոմատ կերպով: Դա անելու համար մենք գրեցինք Ansible գրքույկ, որը մեզ համար կարգավորում է թարմացման ամբողջ գործընթացը.

/usr/lib/postgresql/11/bin/pg_upgrade 
<b>--link </b>
--old-datadir='' --new-datadir='' 
 --old-bindir=''  --new-bindir='' 
 --old-options=' -c config_file=' 
 --new-options=' -c config_file='

Այստեղ կարևոր է նշել, որ թարմացումը սկսելուց առաջ այն պետք է կատարեք պարամետրով -- ստուգելհամոզվելու համար, որ դուք կարող եք թարմացնել: Մեր սցենարը նաև կատարում է կոնֆիգուրացիաների փոխարինում թարմացման տևողության համար: Մեր սցենարն ավարտվեց 30 վայրկյանում, ինչը հիանալի արդյունք է։

Գործարկել Patroni

Երկրորդ խնդիրը լուծելու համար պարզապես նայեք Patroni կոնֆիգուրացիան: Պաշտոնական պահոցն ունի օրինակի կոնֆիգուրացիա initdb-ով, որը պատասխանատու է նոր տվյալների բազայի սկզբնավորման համար, երբ առաջին անգամ գործարկեք Patroni-ն: Բայց քանի որ մենք արդեն ունենք պատրաստի տվյալների բազա, մենք ուղղակի հեռացրինք այս բաժինը կոնֆիգուրացիայից:

Երբ մենք սկսեցինք տեղադրել Patroni-ն արդեն գոյություն ունեցող PostgreSQL կլաստերի վրա և գործարկել այն, մենք հանդիպեցինք նոր խնդրի. երկու սերվերներն էլ գործարկվեցին որպես առաջատար: Patroni-ն ոչինչ չգիտի կլաստերի վաղ վիճակի մասին և փորձում է երկու սերվերները գործարկել որպես նույն անունով երկու առանձին կլաստերներ: Այս խնդիրը լուծելու համար դուք պետք է ջնջեք ստրկական տվյալների հետ կապված գրացուցակը.

rm -rf /var/lib/postgresql/

Սա պետք է արվի միայն ստրուկի վրա:

Երբ մաքուր կրկնօրինակը միացված է, Patroni-ն ստեղծում է բազային պահուստային առաջնորդ և վերականգնում այն ​​կրկնօրինակին, այնուհետև հետևում է ընթացիկ վիճակին՝ ըստ wal logs-ի:

Մեկ այլ դժվարություն, որը մենք հանդիպեցինք, այն է, որ բոլոր PostgreSQL կլաստերները լռելյայն անվանվում են հիմնական: Երբ յուրաքանչյուր կլաստեր ոչինչ չգիտի մյուսի մասին, դա նորմալ է: Բայց երբ դուք ցանկանում եք օգտագործել Patroni, ապա բոլոր կլաստերները պետք է ունենան յուրահատուկ անուն: Լուծումը PostgreSQL կոնֆիգուրացիայի մեջ կլաստերի անունը փոխելն է:

բեռի փորձարկում

Մենք գործարկել ենք մի թեստ, որը մոդելավորում է օգտատերերի փորձը տախտակների վրա: Երբ բեռը հասավ մեր միջին օրական արժեքին, մենք կրկնեցինք ճիշտ նույն թեստը, մենք անջատեցինք մեկ օրինակ PostgreSQL առաջատարի հետ։ Ավտոմատ ձախողումն աշխատեց այնպես, ինչպես մենք ակնկալում էինք. Patroni-ն փոխեց ղեկավարին, Consul-template-ը թարմացրեց PgBouncer-ի կոնֆիգուրացիան և ուղարկեց վերաբեռնման հրաման: Ըստ Grafana-ի մեր գծապատկերների՝ պարզ էր, որ տվյալների բազայի հետ կապի հետ կապված սերվերներից կան 20-30 վայրկյան ուշացումներ և փոքր քանակությամբ սխալներ: Սա նորմալ իրավիճակ է, նման արժեքները ընդունելի են մեր ձախողման համար և միանշանակ ավելի լավն են, քան ծառայության խափանումը:

Պատրոնին բերելով արտադրության

Արդյունքում մենք եկանք հետևյալ պլանի հետ.

  • Տեղադրեք Consul-կաղապարը PgBouncer սերվերների վրա և գործարկեք;
  • PostgreSQL թարմացումներ 11.2 տարբերակի համար;
  • Փոխել կլաստերի անունը;
  • «Պատրոնի կլաստերի» մեկնարկը:

Միևնույն ժամանակ, մեր սխեման մեզ թույլ է տալիս գրեթե ցանկացած պահի նշել առաջին կետը, մենք կարող ենք հերթով հեռացնել յուրաքանչյուր PgBouncer-ը աշխատանքից և տեղադրել և գործարկել դրա վրա հյուպատոս-կաղապար: Այսպիսով, մենք արեցինք:

Արագ տեղակայման համար մենք օգտագործեցինք Ansible-ը, քանի որ մենք արդեն փորձարկել ենք բոլոր գրքույկները թեստային միջավայրում, և ամբողջական սցենարի կատարման ժամանակը յուրաքանչյուր բեկորի համար 1,5-ից 2 րոպե էր: Մենք կարող էինք հերթով տարածել ամեն ինչ յուրաքանչյուր բեկորի վրա՝ առանց մեր ծառայությունը դադարեցնելու, բայց մենք պետք է անջատենք յուրաքանչյուր PostgreSQL մի քանի րոպեով: Այս դեպքում օգտվողները, որոնց տվյալները գտնվում են այս հատվածի վրա, այս պահին չեն կարող լիովին աշխատել, և դա մեզ համար անընդունելի է:

Այս իրավիճակից ելքը պլանային սպասարկումն էր, որը տեղի է ունենում 3 ամիսը մեկ։ Սա պլանավորված աշխատանքի պատուհան է, երբ մենք ամբողջությամբ անջատում ենք մեր ծառայությունը և թարմացնում ենք մեր տվյալների բազայի օրինակները: Մեկ շաբաթ մնաց մինչև հաջորդ պատուհանը, և մենք որոշեցինք պարզապես սպասել և պատրաստվել հետագա: Սպասման ժամանակ մենք լրացուցիչ ապահովեցինք ինքներս մեզ. յուրաքանչյուր PostgreSQL բեկորի համար մենք բարձրացրինք պահեստային կրկնօրինակ՝ վերջին տվյալները չպահպանելու դեպքում, և յուրաքանչյուր բեկորի համար ավելացրինք նոր օրինակ, որը պետք է դառնա նոր կրկնօրինակ Patroni կլաստերում: որպեսզի չկատարվի տվյալների ջնջման հրամանը: Այս ամենը օգնեց նվազագույնի հասցնել սխալի վտանգը:
Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Մենք վերագործարկեցինք մեր ծառայությունը, ամեն ինչ աշխատեց այնպես, ինչպես պետք է, օգտվողները շարունակեցին աշխատել, բայց գրաֆիկների վրա մենք նկատեցինք աննորմալ բարձր ծանրաբեռնվածություն Consul սերվերների վրա:
Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Ինչու՞ մենք դա չտեսանք թեստային միջավայրում: Այս խնդիրը շատ լավ ցույց է տալիս, որ անհրաժեշտ է հետևել Ենթակառուցվածքը որպես ծածկագրի սկզբունքին և կատարելագործել ամբողջ ենթակառուցվածքը՝ փորձարկման միջավայրից մինչև արտադրություն: Հակառակ դեպքում, մեր ստացած խնդիրը շատ հեշտ է ստանալ։ Ինչ է պատահել? Հյուպատոսը սկզբում հայտնվեց արտադրության վրա, այնուհետև թեստային միջավայրերում, արդյունքում թեստային միջավայրերում Consul-ի տարբերակը ավելի բարձր էր, քան արտադրությանը: Հենց թողարկումներից մեկում լուծվեց պրոցեսորի արտահոսքը հյուպատոս-կաղապարի հետ աշխատելիս։ Ուստի մենք պարզապես թարմացրել ենք հյուպատոսը՝ դրանով իսկ լուծելով խնդիրը։

Վերագործարկեք Patroni կլաստերը

Սակայն մենք ստացանք նոր խնդիր, որի մասին չէինք էլ կասկածում։ Հյուպատոսը թարմացնելիս մենք պարզապես հեռացնում ենք Consul հանգույցը կլաստերից՝ օգտագործելով consul leave հրամանը → Patroni-ն միանում է մեկ այլ Consul server-ին → ամեն ինչ աշխատում է: Բայց երբ մենք հասանք Consul կլաստերի վերջին ատյանին և ուղարկեցինք կոնսուլի թողարկման հրամանը, բոլոր Patroni կլաստերները պարզապես վերագործարկվեցին, և գրանցամատյաններում տեսանք հետևյալ սխալը.

ERROR: get_cluster
Traceback (most recent call last):
...
RetryFailedError: 'Exceeded retry deadline'
ERROR: Error communicating with DCS
<b>LOG: database system is shut down</b>

Patroni կլաստերը չկարողացավ առբերել իր կլաստերի մասին տեղեկատվություն և վերագործարկվեց:

Լուծում գտնելու համար մենք կապվեցինք Patroni հեղինակների հետ github-ի խնդրի միջոցով: Նրանք առաջարկեցին բարելավումներ մեր կազմաձևման ֆայլերում.

consul:
 consul.checks: []
bootstrap:
 dcs:
   retry_timeout: 8

Մենք կարողացանք վերարտադրել խնդիրը թեստային միջավայրում և այնտեղ փորձարկեցինք այս տարբերակները, բայց, ցավոք, դրանք չաշխատեցին:

Խնդիրը դեռևս մնում է չլուծված։ Մենք նախատեսում ենք փորձել հետևյալ լուծումները.

  • Օգտագործեք կոնսուլ-գործակալ յուրաքանչյուր Patroni կլաստերային օրինակում;
  • Ուղղեք խնդիրը կոդի մեջ:

Մենք հասկանում ենք, թե որտեղ է տեղի ունեցել սխալը. խնդիրը հավանաբար լռելյայն ժամանակի դադարի օգտագործումն է, որը չի անտեսվում կազմաձևման ֆայլի միջոցով: Երբ վերջին Consul սերվերը հեռացվում է կլաստերից, ամբողջ Consul կլաստերը կախված է մեկ վայրկյանից ավելի, դրա պատճառով Patroni-ն չի կարող ստանալ կլաստերի կարգավիճակը և ամբողջությամբ վերագործարկում է ամբողջ կլաստերը:

Բարեբախտաբար, մենք այլևս սխալների չհանդիպեցինք։

Patroni-ի օգտագործման արդյունքները

Patroni-ի հաջող գործարկումից հետո մենք ավելացրինք լրացուցիչ կրկնօրինակ յուրաքանչյուր կլաստերում: Այժմ յուրաքանչյուր կլաստերում կա քվորումի տեսք՝ մեկ առաջնորդ և երկու կրկնօրինակ, անվտանգության ցանցի համար՝ անջատման ժամանակ ուղեղի պառակտման դեպքում:
Failover Cluster PostgreSQL + Patroni: Իրականացման փորձ

Patroni-ն արտադրության վրա աշխատում է ավելի քան երեք ամիս։ Այս ընթացքում նա արդեն հասցրել է օգնել մեզ։ Վերջերս AWS-ում մահացավ կլաստերներից մեկի առաջնորդը, ավտոմատ ֆայլովերը աշխատեց, և օգտատերերը շարունակեցին աշխատել։ Պատրոնը կատարեց իր հիմնական խնդիրը.

Patroni-ի օգտագործման փոքր ամփոփում.

  • Կազմաձևման փոփոխությունների հեշտությունը: Բավական է փոխել կոնֆիգուրացիան մեկ օրինակով, և այն կքաշվի մինչև ամբողջ կլաստերը: Եթե ​​նոր կոնֆիգուրացիան կիրառելու համար անհրաժեշտ է վերաբեռնում, ապա Patroni-ն ձեզ կտեղեկացնի: Patroni-ն կարող է վերագործարկել ամբողջ կլաստերը մեկ հրամանով, ինչը նույնպես շատ հարմար է:
  • Ավտոմատ ձախողումն աշխատում է և արդեն հասցրել է օգնել մեզ:
  • PostgreSQL-ի թարմացում՝ առանց հավելվածի ընդհատման: Դուք նախ պետք է թարմացնեք կրկնօրինակները նոր տարբերակով, ապա փոխեք առաջնորդը Patroni կլաստերի մեջ և թարմացնեք հին առաջնորդը: Այս դեպքում տեղի է ունենում ավտոմատ ձախողման անհրաժեշտ փորձարկում:

Source: www.habr.com

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