Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Sa artikulong sasabihin ko sa iyo kung paano namin nilapitan ang isyu ng PostgreSQL fault tolerance, kung bakit ito naging mahalaga para sa amin at kung ano ang nangyari sa huli.

Mayroon kaming napaka-load na serbisyo: 2,5 milyong user sa buong mundo, 50K+ aktibong user araw-araw. Ang mga server ay matatagpuan sa Amazone sa isang rehiyon ng Ireland: 100+ iba't ibang mga server ang patuloy na gumagana, kung saan halos 50 ay may mga database.

Ang buong backend ay isang malaking monolithic stateful na Java application na nagpapanatili ng patuloy na koneksyon sa websocket sa kliyente. Kapag maraming user ang nagtatrabaho sa parehong board nang sabay-sabay, nakikita nilang lahat ang mga pagbabago sa real time, dahil isinusulat namin ang bawat pagbabago sa database. Mayroon kaming humigit-kumulang 10K kahilingan bawat segundo sa aming mga database. Sa peak load sa Redis, nagsusulat kami ng 80-100K na kahilingan bawat segundo.
Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Bakit kami lumipat mula sa Redis patungo sa PostgreSQL

Sa una, ang aming serbisyo ay nagtrabaho sa Redis, isang key-value store na nag-iimbak ng lahat ng data sa RAM ng server.

Mga kalamangan ng Redis:

  1. Mataas na bilis ng pagtugon, dahil lahat ay nakaimbak sa memorya;
  2. Dali ng backup at pagtitiklop.

Kahinaan ng Redis para sa amin:

  1. Walang tunay na transaksyon. Sinubukan naming gayahin ang mga ito sa antas ng aming aplikasyon. Sa kasamaang palad, hindi ito palaging gumagana nang maayos at nangangailangan ng pagsusulat ng napakakomplikadong code.
  2. Ang dami ng data ay nililimitahan ng dami ng memorya. Habang tumataas ang dami ng data, lalago ang memorya, at, sa huli, tatakbo tayo sa mga katangian ng napiling instance, na sa AWS ay nangangailangan ng pagpapahinto sa aming serbisyo upang baguhin ang uri ng instance.
  3. Ito ay kinakailangan upang patuloy na mapanatili ang isang mababang antas ng latency, dahil. mayroon kaming napakaraming bilang ng mga kahilingan. Ang pinakamainam na antas ng pagkaantala para sa amin ay 17-20 ms. Sa antas na 30-40 ms, nakakakuha kami ng mahabang tugon sa mga kahilingan mula sa aming aplikasyon at pagkasira ng serbisyo. Sa kasamaang-palad, nangyari ito sa amin noong Setyembre 2018, nang ang isa sa mga instance na may Redis para sa ilang kadahilanan ay nakatanggap ng latency nang 2 beses na higit sa karaniwan. Upang malutas ang isyu, itinigil namin ang serbisyo sa kalagitnaan ng araw para sa hindi nakaiskedyul na pagpapanatili at pinalitan ang may problemang instance ng Redis.
  4. Madaling makakuha ng hindi pagkakapare-pareho ng data kahit na may maliliit na error sa code at pagkatapos ay gumugol ng maraming oras sa pagsulat ng code upang itama ang data na ito.

Isinasaalang-alang namin ang mga kahinaan at napagtanto namin na kailangan naming lumipat sa isang bagay na mas maginhawa, na may mga normal na transaksyon at mas kaunting pag-asa sa latency. Nagsagawa ng pananaliksik, sinuri ang maraming mga opsyon at pinili ang PostgreSQL.

Lumipat kami sa isang bagong database sa loob ng 1,5 taon na at inilipat lamang ang isang maliit na bahagi ng data, kaya ngayon kami ay nagtatrabaho nang sabay-sabay sa Redis at PostgreSQL. Higit pang impormasyon tungkol sa mga yugto ng paglipat at paglipat ng data sa pagitan ng mga database ay nakasulat sa artikulo ng aking kasamahan.

Noong una kaming nagsimulang lumipat, direktang gumana ang aming application sa database at na-access ang master Redis at PostgreSQL. Ang PostgreSQL cluster ay binubuo ng isang master at isang replica na may asynchronous na pagtitiklop. Ganito ang hitsura ng scheme ng database:
Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Pagpapatupad ng PgBouncer

Habang kami ay gumagalaw, ang produkto ay umuunlad din: ang bilang ng mga gumagamit at ang bilang ng mga server na nagtrabaho sa PostgreSQL ay tumaas, at kami ay nagsimulang magkulang ng mga koneksyon. Lumilikha ang PostgreSQL ng isang hiwalay na proseso para sa bawat koneksyon at gumagamit ng mga mapagkukunan. Maaari mong dagdagan ang bilang ng mga koneksyon hanggang sa isang tiyak na punto, kung hindi, may pagkakataong makakuha ng suboptimal na pagganap ng database. Ang perpektong opsyon sa ganoong sitwasyon ay ang pumili ng isang manager ng koneksyon na tatayo sa harap ng base.

Mayroon kaming dalawang pagpipilian para sa manager ng koneksyon: Pgpool at PgBouncer. Ngunit ang una ay hindi sumusuporta sa transactional mode ng pagtatrabaho sa database, kaya pinili namin ang PgBouncer.

Nai-set up namin ang sumusunod na pamamaraan ng trabaho: ina-access ng aming application ang isang PgBouncer, sa likod nito ay mga master ng PostgreSQL, at sa likod ng bawat master ay isang replica na may asynchronous na pagtitiklop.
Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Kasabay nito, hindi namin maiimbak ang buong dami ng data sa PostgreSQL at ang bilis ng pagtatrabaho sa database ay mahalaga para sa amin, kaya nagsimula kaming mag-shard ng PostgreSQL sa antas ng aplikasyon. Ang scheme na inilarawan sa itaas ay medyo maginhawa para dito: kapag nagdaragdag ng bagong PostgreSQL shard, sapat na upang i-update ang configuration ng PgBouncer at ang application ay maaaring gumana kaagad sa bagong shard.

Failover ng PgBouncer

Ang scheme na ito ay gumana hanggang sa sandaling namatay ang nag-iisang PgBouncer instance. Nasa AWS tayo, kung saan tumatakbo ang lahat ng instance sa hardware na pana-panahong namamatay. Sa ganitong mga kaso, lilipat lang ang instance sa bagong hardware at gagana muli. Nangyari ito sa PgBouncer, ngunit naging hindi ito available. Ang resulta ng taglagas na ito ay ang hindi magagamit ng aming serbisyo sa loob ng 25 minuto. Inirerekomenda ng AWS ang paggamit ng user-side redundancy para sa mga ganitong sitwasyon, na hindi ipinatupad sa ating bansa noong panahong iyon.

Pagkatapos noon, seryoso naming pinag-isipan ang tungkol sa fault tolerance ng PgBouncer at PostgreSQL cluster, dahil maaaring mangyari ang isang katulad na sitwasyon sa anumang instance sa aming AWS account.

Binuo namin ang PgBouncer fault tolerance scheme gaya ng sumusunod: lahat ng application server ay nag-a-access sa Network Load Balancer, kung saan mayroong dalawang PgBouncer. Ang bawat PgBouncer ay tumitingin sa parehong PostgreSQL master ng bawat shard. Kung maganap muli ang isang AWS instance crash, ang lahat ng trapiko ay ire-redirect sa pamamagitan ng isa pang PgBouncer. Ang Network Load Balancer failover ay ibinibigay ng AWS.

Pinapadali ng scheme na ito ang pagdaragdag ng mga bagong server ng PgBouncer.
Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Lumikha ng isang PostgreSQL Failover Cluster

Kapag nilulutas ang problemang ito, isinasaalang-alang namin ang iba't ibang mga opsyon: self-written failover, repmgr, AWS RDS, Patroni.

Mga script na isinulat sa sarili

Maaari nilang subaybayan ang gawain ng master at, kung sakaling mabigo ito, i-promote ang replica sa master at i-update ang configuration ng PgBouncer.

Ang mga bentahe ng diskarteng ito ay ang maximum na pagiging simple, dahil ikaw mismo ang sumulat ng mga script at eksaktong nauunawaan kung paano gumagana ang mga ito.

Cons:

  • Maaaring hindi namatay ang master, sa halip ay maaaring magkaroon ng pagkabigo sa network. Failover, walang kamalayan sa mga ito, ay i-promote ang replika sa master, habang ang matandang master ay patuloy na gagana. Bilang resulta, kukuha kami ng dalawang server sa tungkulin ng master at hindi namin malalaman kung alin sa kanila ang may pinakabagong up-to-date na data. Ang sitwasyong ito ay tinatawag ding split-brain;
  • Naiwan kaming walang tugon. Sa aming configuration, ang master at isang replica, pagkatapos lumipat, ang replica ay gumagalaw pataas sa master at wala na kaming mga replica, kaya kailangan naming manu-manong magdagdag ng bagong replica;
  • Kailangan namin ng karagdagang pagsubaybay sa operasyon ng failover, habang mayroon kaming 12 PostgreSQL shards, na nangangahulugang kailangan naming subaybayan ang 12 cluster. Sa pagtaas ng bilang ng mga shards, dapat mo ring tandaan na i-update ang failover.

Ang self-written failover ay mukhang napakakomplikado at nangangailangan ng hindi walang kuwentang suporta. Sa isang cluster ng PostgreSQL, ito ang magiging pinakamadaling opsyon, ngunit hindi ito sukat, kaya hindi ito angkop para sa amin.

Repmgr

Replication Manager para sa mga PostgreSQL cluster, na maaaring pamahalaan ang pagpapatakbo ng isang PostgreSQL cluster. Kasabay nito, wala itong awtomatikong failover sa labas ng kahon, kaya para sa trabaho kakailanganin mong isulat ang iyong sariling "wrapper" sa ibabaw ng tapos na solusyon. Kaya ang lahat ay maaaring maging mas kumplikado kaysa sa mga self-written na script, kaya hindi na namin sinubukan ang Repmgr.

AWS RDS

Sinusuportahan ang lahat ng kailangan namin, alam kung paano gumawa ng mga backup at nagpapanatili ng isang pool ng mga koneksyon. Mayroon itong awtomatikong paglipat: kapag namatay ang master, ang replica ang magiging bagong master, at binago ng AWS ang dns record sa bagong master, habang ang mga replika ay maaaring matatagpuan sa iba't ibang AZ.

Kasama sa mga disadvantage ang kakulangan ng mga pinong pagsasaayos. Bilang isang halimbawa ng fine tuning: ang aming mga instance ay may mga paghihigpit para sa mga koneksyon sa tcp, na, sa kasamaang-palad, ay hindi maaaring gawin sa RDS:

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

Bilang karagdagan, ang AWS RDS ay halos dalawang beses na mas mahal kaysa sa regular na presyo ng halimbawa, na siyang pangunahing dahilan sa pag-abandona sa solusyon na ito.

Patroni

Ito ay isang template ng python para sa pamamahala ng PostgreSQL na may mahusay na dokumentasyon, awtomatikong failover at source code sa github.

Mga kalamangan ng Patroni:

  • Ang bawat parameter ng pagsasaayos ay inilarawan, ito ay malinaw kung paano ito gumagana;
  • Ang awtomatikong failover ay gumagana sa labas ng kahon;
  • Nakasulat sa python, at dahil tayo mismo ang sumusulat ng marami sa python, magiging mas madali para sa atin na harapin ang mga problema at, marahil, kahit na tumulong sa pagbuo ng proyekto;
  • Ganap na namamahala sa PostgreSQL, nagbibigay-daan sa iyong baguhin ang configuration sa lahat ng node ng cluster nang sabay-sabay, at kung kailangang i-restart ang cluster upang mailapat ang bagong configuration, maaari itong gawin muli gamit ang Patroni.

Cons:

  • Hindi malinaw sa dokumentasyon kung paano magtrabaho nang tama sa PgBouncer. Bagama't mahirap tawagan itong minus, dahil ang gawain ng Patroni ay pamahalaan ang PostgreSQL, at kung paano mapupunta ang mga koneksyon sa Patroni ay problema na natin;
  • Mayroong ilang mga halimbawa ng pagpapatupad ng Patroni sa malalaking volume, habang mayroong maraming mga halimbawa ng pagpapatupad mula sa simula.

Bilang resulta, pinili namin si Patroni para gumawa ng failover cluster.

Proseso ng Pagpapatupad ng Patroni

Bago ang Patroni, mayroon kaming 12 PostgreSQL shards sa isang configuration ng isang master at isang replica na may asynchronous replication. Na-access ng mga server ng application ang mga database sa pamamagitan ng Network Load Balancer, sa likod nito ay dalawang pagkakataon na may PgBouncer, at sa likod nito ay ang lahat ng mga PostgreSQL server.
Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Para ipatupad ang Patroni, kailangan naming pumili ng distributed storage cluster configuration. Gumagana si Patroni sa mga distributed configuration storage system tulad ng etcd, Zookeeper, Consul. Mayroon lang kaming ganap na cluster ng Consul sa merkado, na gumagana kasabay ng Vault at hindi na namin ito ginagamit. Isang magandang dahilan para simulan ang paggamit ng Consul para sa layunin nito.

Paano gumagana si Patroni sa Consul

Mayroon kaming isang Consul cluster, na binubuo ng tatlong node, at isang Patroni cluster, na binubuo ng isang pinuno at isang replica (sa Patroni, ang master ay tinatawag na cluster leader, at ang mga alipin ay tinatawag na mga replika). Ang bawat instance ng Patroni cluster ay patuloy na nagpapadala ng impormasyon tungkol sa estado ng cluster sa Consul. Samakatuwid, mula sa Consul palagi mong malalaman ang kasalukuyang configuration ng Patroni cluster at kung sino ang pinuno sa ngayon.

Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Upang ikonekta ang Patroni sa Consul, sapat na upang pag-aralan ang opisyal na dokumentasyon, na nagsasabing kailangan mong tukuyin ang isang host sa http o https na format, depende sa kung paano kami nakikipagtulungan sa Consul, at ang scheme ng koneksyon, opsyonal:

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

Mukhang simple, ngunit dito nagsisimula ang mga pitfalls. Sa Consul, nagtatrabaho kami sa isang secure na koneksyon sa pamamagitan ng https at ang aming connection config ay magiging ganito:

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

Ngunit hindi iyon gumagana. Sa startup, hindi makakonekta si Patroni sa Consul, dahil sinusubukan pa rin nitong dumaan sa http.

Ang source code ng Patroni ay nakatulong sa pagharap sa problema. Buti na lang nakasulat sa python. Ito ay lumalabas na ang parameter ng host ay hindi na-parse sa anumang paraan, at ang protocol ay dapat na tinukoy sa scheme. Ganito ang hitsura ng gumaganang configuration block para sa pakikipagtulungan sa Consul para sa amin:

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

konsul-template

Kaya, pinili namin ang imbakan para sa pagsasaayos. Ngayon ay kailangan nating maunawaan kung paano lilipat ng PgBouncer ang configuration nito kapag binago ang pinuno sa cluster ng Patroni. Walang sagot sa tanong na ito sa dokumentasyon, dahil. doon, sa prinsipyo, ang pakikipagtulungan sa PgBouncer ay hindi inilarawan.

Sa paghahanap ng solusyon, nakakita kami ng isang artikulo (sa kasamaang palad ay hindi ko maalala ang pamagat) kung saan nakasulat na ang Π‘onsul-template ay nakatulong ng malaki sa pagpapares ng PgBouncer at Patroni. Nag-udyok ito sa amin na siyasatin kung paano gumagana ang Consul-template.

Lumalabas na patuloy na sinusubaybayan ng Consul-template ang configuration ng PostgreSQL cluster sa Consul. Kapag nagbago ang pinuno, ina-update nito ang configuration ng PgBouncer at nagpapadala ng command para i-reload ito.

Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Ang isang malaking plus ng template ay na ito ay naka-imbak bilang code, kaya kapag nagdagdag ng isang bagong shard, ito ay sapat na upang gumawa ng isang bagong commit at awtomatikong i-update ang template, na sumusuporta sa Infrastructure bilang code na prinsipyo.

Bagong arkitektura kasama si Patroni

Bilang resulta, nakuha namin ang sumusunod na pamamaraan ng trabaho:
Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Ina-access ng lahat ng mga server ng application ang balancer β†’ mayroong dalawang pagkakataon ng PgBouncer sa likod nito β†’ sa bawat pagkakataon, inilunsad ang Consul-template, na sinusubaybayan ang katayuan ng bawat cluster ng Patroni at sinusubaybayan ang kaugnayan ng config ng PgBouncer, na nagpapadala ng mga kahilingan sa kasalukuyang pinuno ng bawat kumpol.

Manu-manong pagsubok

Pinatakbo namin ang scheme na ito bago ito ilunsad sa isang maliit na kapaligiran ng pagsubok at sinuri ang pagpapatakbo ng awtomatikong paglipat. Binuksan nila ang board, inilipat ang sticker, at sa sandaling iyon ay "pinatay" nila ang pinuno ng kumpol. Sa AWS, ito ay kasing simple ng pag-shut down ng instance sa pamamagitan ng console.

Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Bumalik ang sticker sa loob ng 10-20 segundo, at pagkatapos ay muling nagsimulang gumalaw nang normal. Nangangahulugan ito na gumana nang tama ang cluster ng Patroni: binago nito ang pinuno, ipinadala ang impormasyon sa Π‘onsul, at agad na kinuha ng Π‘onsul-template ang impormasyong ito, pinalitan ang configuration ng PgBouncer at ipinadala ang command na i-reload.

Paano mabuhay sa ilalim ng mataas na pagkarga at panatilihing minimal ang downtime?

Ang lahat ay gumagana nang perpekto! Ngunit may mga bagong tanong: Paano ito gagana sa ilalim ng mataas na pagkarga? Paano mabilis at ligtas na ilunsad ang lahat sa produksyon?

Ang kapaligiran ng pagsubok kung saan nagsasagawa kami ng pagsubok sa pagkarga ay tumutulong sa amin na sagutin ang unang tanong. Ito ay ganap na magkapareho sa produksyon sa mga tuntunin ng arkitektura at nakabuo ng data ng pagsubok na humigit-kumulang katumbas ng dami sa produksyon. Nagpasya kaming "patayin" lamang ang isa sa mga master ng PostgreSQL sa panahon ng pagsubok at tingnan kung ano ang mangyayari. Ngunit bago iyon, mahalagang suriin ang awtomatikong pag-roll, dahil sa kapaligirang ito mayroon kaming ilang mga PostgreSQL shards, kaya makakakuha kami ng mahusay na pagsubok ng mga script ng pagsasaayos bago ang paggawa.

Ang parehong mga gawain ay mukhang ambisyoso, ngunit mayroon kaming PostgreSQL 9.6. Maaari ba tayong mag-upgrade kaagad sa 11.2?

Nagpasya kaming gawin ito sa 2 hakbang: mag-upgrade muna sa 11.2, pagkatapos ay ilunsad ang Patroni.

Pag-update ng PostgreSQL

Upang mabilis na i-update ang bersyon ng PostgreSQL, gamitin ang opsyon -k, kung saan ang mga hard link ay nilikha sa disk at hindi na kailangang kopyahin ang iyong data. Sa mga base na 300-400 GB, ang pag-update ay tumatagal ng 1 segundo.

Marami kaming shards, kaya kailangang awtomatikong gawin ang pag-update. Para magawa ito, nagsulat kami ng Ansible playbook na humahawak sa buong proseso ng pag-update para sa amin:

/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='

Mahalagang tandaan dito na bago simulan ang pag-upgrade, dapat mong gawin ito gamit ang parameter --suriinpara makasigurado kang makakapag-upgrade. Ginagawa rin ng aming script ang pagpapalit ng mga config para sa tagal ng pag-upgrade. Nakumpleto ang aming script sa loob ng 30 segundo, na isang mahusay na resulta.

Ilunsad ang Patroni

Upang malutas ang pangalawang problema, tingnan lamang ang pagsasaayos ng Patroni. Ang opisyal na repository ay may halimbawang configuration na may initdb, na responsable para sa pagsisimula ng bagong database noong una mong simulan ang Patroni. Ngunit dahil mayroon na kaming handa na database, inalis na lang namin ang seksyong ito sa pagsasaayos.

Noong sinimulan naming i-install ang Patroni sa isang umiiral nang PostgreSQL cluster at patakbuhin ito, nagkaroon kami ng bagong problema: nagsimula ang parehong mga server bilang pinuno. Walang alam si Patroni tungkol sa maagang estado ng cluster at sinusubukang simulan ang parehong mga server bilang dalawang magkahiwalay na cluster na may parehong pangalan. Upang malutas ang problemang ito, kailangan mong tanggalin ang direktoryo na may data sa alipin:

rm -rf /var/lib/postgresql/

Ito ay kailangang gawin lamang sa alipin!

Kapag nakakonekta ang isang malinis na replica, gagawa si Patroni ng basebackup leader at ibinabalik ito sa replica, at pagkatapos ay aabutan ang kasalukuyang estado ayon sa mga wal log.

Ang isa pang kahirapan na naranasan namin ay ang lahat ng PostgreSQL cluster ay pinangalanang pangunahing bilang default. Kapag ang bawat kumpol ay walang alam tungkol sa isa pa, ito ay normal. Ngunit kapag gusto mong gamitin ang Patroni, ang lahat ng mga kumpol ay dapat magkaroon ng isang natatanging pangalan. Ang solusyon ay baguhin ang pangalan ng kumpol sa pagsasaayos ng PostgreSQL.

pagsubok sa pagkarga

Naglunsad kami ng pagsubok na ginagaya ang karanasan ng user sa mga board. Nang maabot ng load ang aming average na pang-araw-araw na halaga, inulit namin ang eksaktong parehong pagsubok, pinatay namin ang isang instance kasama ang pinuno ng PostgreSQL. Ang awtomatikong failover ay gumana tulad ng inaasahan namin: Binago ni Patroni ang pinuno, na-update ng Consul-template ang configuration ng PgBouncer at nagpadala ng command na mag-reload. Ayon sa aming mga graph sa Grafana, malinaw na may mga pagkaantala ng 20-30 segundo at kaunting mga error mula sa mga server na nauugnay sa koneksyon sa database. Ito ay isang normal na sitwasyon, ang mga naturang halaga ay katanggap-tanggap para sa aming failover at tiyak na mas mahusay kaysa sa downtime ng serbisyo.

Dinadala si Patroni sa produksyon

Bilang resulta, nakabuo kami ng sumusunod na plano:

  • I-deploy ang Consul-template sa mga server ng PgBouncer at ilunsad;
  • Mga update ng PostgreSQL sa bersyon 11.2;
  • Baguhin ang pangalan ng kumpol;
  • Pagsisimula ng Patroni Cluster.

Kasabay nito, ang aming scheme ay nagbibigay-daan sa amin na gawin ang unang punto halos anumang oras, maaari naming alisin ang bawat PgBouncer mula sa trabaho nang magkakasunod at mag-deploy at magpatakbo ng consul-template dito. Kaya ginawa namin.

Para sa mabilis na pag-deploy, ginamit namin ang Ansible, dahil nasubukan na namin ang lahat ng playbook sa isang pagsubok na kapaligiran, at ang oras ng pagpapatupad ng buong script ay mula 1,5 hanggang 2 minuto para sa bawat shard. Maaari naming ilunsad ang lahat sa turn sa bawat shard nang hindi humihinto sa aming serbisyo, ngunit kailangan naming i-off ang bawat PostgreSQL sa loob ng ilang minuto. Sa kasong ito, ang mga user na ang data ay nasa shard na ito ay hindi ganap na gumana sa oras na ito, at ito ay hindi katanggap-tanggap para sa amin.

Ang paraan sa labas ng sitwasyong ito ay ang nakaplanong pagpapanatili, na nagaganap tuwing 3 buwan. Ito ay isang window para sa naka-iskedyul na trabaho, kapag ganap naming isinara ang aming serbisyo at i-upgrade ang aming mga instance sa database. May isang linggo pa bago ang susunod na window, at nagpasya kaming maghintay at maghanda pa. Sa panahon ng paghihintay, tiniyak din namin ang aming sarili: para sa bawat PostgreSQL shard, nagtaas kami ng ekstrang replica kung sakaling mabigo na panatilihin ang pinakabagong data, at nagdagdag ng bagong instance para sa bawat shard, na dapat maging bagong replica sa Patroni cluster, upang hindi magsagawa ng utos na tanggalin ang data. Ang lahat ng ito ay nakatulong upang mabawasan ang panganib ng pagkakamali.
Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Sinimulan namin muli ang aming serbisyo, gumana ang lahat ayon sa nararapat, nagpatuloy ang mga gumagamit, ngunit sa mga graph napansin namin ang isang abnormal na mataas na pagkarga sa mga server ng Consul.
Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Bakit hindi natin ito nakita sa kapaligiran ng pagsubok? Ang problemang ito ay napakahusay na naglalarawan na ito ay kinakailangan upang sundin ang Infrastructure bilang code prinsipyo at pinuhin ang buong imprastraktura, mula sa pagsubok na kapaligiran sa produksyon. Kung hindi, napakadaling makuha ang problemang nakuha namin. Anong nangyari? Unang lumitaw ang Consul sa produksyon, at pagkatapos ay sa mga kapaligiran ng pagsubok, bilang resulta, sa mga kapaligiran ng pagsubok, ang bersyon ng Consul ay mas mataas kaysa sa produksyon. Sa isa lamang sa mga release, nalutas ang isang pagtagas ng CPU kapag nagtatrabaho sa consul-template. Samakatuwid, nag-update lang kami ng Consul, kaya nalutas ang problema.

I-restart ang Patroni cluster

Gayunpaman, nagkaroon kami ng bagong problema, na hindi namin pinaghihinalaan. Kapag ina-update ang Consul, inaalis lang namin ang Consul node mula sa cluster gamit ang consul leave command β†’ Patroni connects to another Consul server β†’ everything works. Ngunit nang maabot namin ang huling instance ng cluster ng Consul at ipinadala ang utos ng consul leave dito, ang lahat ng mga cluster ng Patroni ay nag-restart, at sa mga log nakita namin ang sumusunod na error:

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>

Hindi nakuha ng Patroni cluster ang impormasyon tungkol sa cluster nito at nag-restart.

Upang makahanap ng solusyon, nakipag-ugnayan kami sa mga may-akda ng Patroni sa pamamagitan ng isang isyu sa github. Iminungkahi nila ang mga pagpapabuti sa aming mga configuration file:

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

Nagawa naming kopyahin ang problema sa isang kapaligiran ng pagsubok at sinubukan ang mga opsyong ito doon, ngunit sa kasamaang-palad ay hindi ito gumana.

Ang problema ay nananatiling hindi nalutas. Plano naming subukan ang mga sumusunod na solusyon:

  • Gumamit ng Consul-agent sa bawat Patroni cluster instance;
  • Ayusin ang isyu sa code.

Nauunawaan namin kung saan nangyari ang error: ang problema ay marahil ang paggamit ng default na timeout, na hindi na-override sa pamamagitan ng configuration file. Kapag ang huling server ng Consul ay tinanggal mula sa cluster, ang buong cluster ng Consul ay nag-hang ng higit sa isang segundo, dahil dito, hindi makuha ni Patroni ang katayuan ng cluster at ganap na i-restart ang buong cluster.

Sa kabutihang palad, hindi na kami nakatagpo ng anumang mga pagkakamali.

Mga resulta ng paggamit ng Patroni

Pagkatapos ng matagumpay na paglulunsad ng Patroni, nagdagdag kami ng karagdagang replika sa bawat kumpol. Ngayon sa bawat kumpol ay may pagkakahawig ng isang korum: isang pinuno at dalawang replika, upang maging ligtas sa kaso ng split-brain kapag lumipat.
Failover Cluster PostgreSQL + Patroni. Karanasan sa pagpapatupad

Si Patroni ay nagtatrabaho sa produksyon nang higit sa tatlong buwan. Sa panahong ito, nagawa na niyang tulungan kami. Kamakailan, namatay ang pinuno ng isa sa mga kumpol sa AWS, gumana ang awtomatikong failover at patuloy na gumana ang mga user. Natupad ni Patroni ang pangunahing gawain nito.

Isang maliit na buod ng paggamit ng Patroni:

  • Dali ng mga pagbabago sa configuration. Ito ay sapat na upang baguhin ang configuration sa isang pagkakataon at ito ay mahila hanggang sa buong cluster. Kung kinakailangan ang pag-reboot upang mailapat ang bagong configuration, ipapaalam sa iyo ni Patroni. Maaaring i-restart ni Patroni ang buong kumpol gamit ang isang utos, na napakaginhawa rin.
  • Gumagana ang awtomatikong failover at nagawang tumulong sa amin.
  • PostgreSQL update nang walang application downtime. Dapat mo munang i-update ang mga replika sa bagong bersyon, pagkatapos ay baguhin ang pinuno sa cluster ng Patroni at i-update ang lumang pinuno. Sa kasong ito, nangyayari ang kinakailangang pagsubok ng awtomatikong failover.

Pinagmulan: www.habr.com

Magdagdag ng komento