{"id":35706,"date":"2019-10-31T22:05:50","date_gmt":"2019-10-31T19:05:50","guid":{"rendered":"https:\/\/prohoster.info\/blog\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya\/"},"modified":"2026-05-18T20:58:46","modified_gmt":"2026-05-18T18:58:46","slug":"otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya","status":"publish","type":"post","link":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya","title":{"rendered":"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>\u00cen acest articol, voi explica cum am abordat problema rezilien\u021bei PostgreSQL, de ce a devenit important\u0103 pentru noi \u0219i ce am realizat \u00een final.<\/p>\n<p>Avem un serviciu cu o \u00eenc\u0103rcare mare: 2,5 milioane de utilizatori la nivel mondial, 50K+ utilizatori activi \u00een fiecare zi. Serverele noastre se afl\u0103 \u00een Amazone, \u00eentr-o singur\u0103 regiune din Irlanda: avem constant \u00een func\u021biune 100+ diverse servere, dintre care aproape 50 sunt servere cu baze de date.<\/p>\n<p>\u00centregul backend este o aplica\u021bie monolitic\u0103 mare, stateful, scris\u0103 \u00een Java, care men\u021bine o conexiune websocket constant\u0103 cu clientul. C\u00e2nd mai mul\u021bi utilizatori lucreaz\u0103 simultan pe aceea\u0219i tabl\u0103, to\u021bi v\u0103d modific\u0103rile \u00een timp real, deoarece fiecare modificare este salvat\u0103 \u00een baza de date. Avem aproximativ 10K cereri pe secund\u0103 c\u0103tre bazele noastre de date. \u00cen timpul unui v\u00e2rf de \u00eenc\u0103rcare, \u00een Redis scriem \u00eentre 80-100K cereri pe secund\u0103.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/443f85815b0560fade7db5b639942935.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><br \/>\n<a rel=\"nofollow\" name=\"habracut\"><\/a><\/p>\n<h2>De ce am trecut de la Redis la PostgreSQL<\/h2>\n<p>Ini\u021bial, serviciul nostru a func\u021bionat cu Redis, un magazin de tip key-value care stocheaz\u0103 toate datele \u00een memoria RAM. <a href=\"https:\/\/prohoster.info\/ro\/server\/\">server<\/a>.<\/p>\n<p>Avantajele Redis:<\/p>\n<ol>\n<li>Vitez\u0103 de r\u0103spuns foarte rapid\u0103, deoarece totul este stocat \u00een memorie;<\/li>\n<li>Facilitatea de backup \u0219i replicare.<\/li>\n<\/ol>\n<p>Dezavantajele Redis pentru noi:<\/p>\n<ol>\n<li>Lipsa tranzac\u021biilor reale. Am \u00eencercat s\u0103 le imit\u0103m la nivelul aplica\u021biei noastre. Din p\u0103cate, nu a func\u021bionat \u00eentotdeauna bine \u0219i a necesitat scrierea unui cod foarte complex.<\/li>\n<li>Volumul de date este limitat de capacitatea memoriei. Pe m\u0103sur\u0103 ce cantitatea de date cre\u0219te, memoria va cre\u0219te, iar \u00een cele din urm\u0103 vom ajunge la limita caracteristicilor instan\u021bei alese, ceea ce \u00een AWS necesit\u0103 oprirea serviciului nostru pentru a schimba tipul de instan\u021b\u0103.<\/li>\n<li>Este necesar s\u0103 men\u021binem constant un nivel sc\u0103zut de laten\u021b\u0103, deoarece avem un num\u0103r foarte mare de cereri. Nivelul optim de laten\u021b\u0103 pentru noi este de 17-20 ms. La un nivel de 30-40 ms, primim r\u0103spunsuri lente la cererile aplica\u021biei noastre \u0219i degradarea serviciului. Din p\u0103cate, acest lucru s-a \u00eent\u00e2mplat \u00een septembrie 2018, c\u00e2nd una dintre instan\u021bele Redis a avut dintr-un motiv oarecare o laten\u021b\u0103 de dou\u0103 ori mai mare dec\u00e2t de obicei. Pentru a rezolva problema, am oprit serviciul \u00een mijlocul zilei lucr\u0103toare pentru \u00eentre\u021binere neplanificat\u0103 \u0219i am \u00eenlocuit instan\u021ba problematic\u0103 Redis.<\/li>\n<li>Este u\u0219or s\u0103 ob\u021bii inconsisten\u021be \u00een date chiar \u0219i \u00een cazul unor erori minore \u00een cod \u0219i apoi s\u0103 cheltui mult timp scriind cod pentru a corecta aceste date.<\/li>\n<\/ol>\n<p>Am avut \u00een vedere dezavantajele \u0219i am realizat c\u0103 este necesar s\u0103 ne mut\u0103m pe ceva mai convenabil, cu tranzac\u021bii normale \u0219i o dependen\u021b\u0103 mai mic\u0103 de laten\u021b\u0103. Am efectuat cercet\u0103ri, am analizat numeroase op\u021biuni \u0219i am ales PostgreSQL.<\/p>\n<p>Ne mut\u0103m pe noua baz\u0103 de date de 1,5 ani \u0219i am transferat doar o mic\u0103 parte din date, a\u0219a c\u0103 acum lucr\u0103m simultan cu Redis \u0219i PostgreSQL. Detalii despre etapele mut\u0103rii \u0219i tranzi\u021bia datelor \u00eentre baze sunt scrise \u00een <a href=\"https:\/\/habr.com\/ru\/company\/miro\/blog\/437826\/\" rel=\"nofollow\">articolul colegului meu<\/a>.<\/p>\n<p>C\u00e2nd am \u00eenceput s\u0103 ne mut\u0103m, aplica\u021bia noastr\u0103 lucra direct cu baza de date \u0219i se conecta la masterul Redis \u0219i PostgreSQL. Clusterul PostgreSQL era format dintr-un master \u0219i o replic\u0103 cu replicare asincron\u0103. A\u0219a ar\u0103ta schema de lucru cu bazele:<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/674dd77de4c8b48a946c9f64c0b2fdd1.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<h2>Implementarea PgBouncer<\/h2>\n<p>\u00cen timp ce ne mutam, produsul a evoluat \u0219i num\u0103rul utilizatorilor \u0219i al serverelor care lucrau cu PostgreSQL a crescut, iar noi am avut o lips\u0103 de conexiuni. PostgreSQL creeaz\u0103 un proces separat pentru fiecare conexiune \u0219i consum\u0103 resurse. Num\u0103rul de conexiuni poate fi crescut doar p\u00e2n\u0103 la un anumit punct, altfel exist\u0103 riscul de a ob\u021bine o func\u021bionare neoptimizat\u0103 a bazei de date. O op\u021biune ideal\u0103 \u00een aceast\u0103 situa\u021bie ar fi alegerea unui manager de conexiuni care s\u0103 se interpune \u00eentre baz\u0103.<\/p>\n<p>Am avut dou\u0103 op\u021biuni pentru managerul de conexiuni: Pgpool \u0219i PgBouncer. Dar primul nu suport\u0103 modul de lucru tranzac\u021bional cu baza de date, a\u0219a c\u0103 am ales PgBouncer.<\/p>\n<p>Am configurat urm\u0103toarea schem\u0103 de lucru: aplica\u021bia noastr\u0103 se conecteaz\u0103 la un PgBouncer, \u00een spatele c\u0103ruia se afl\u0103 masterele PostgreSQL, iar \u00een spatele fiec\u0103rui master exist\u0103 o replic\u0103 cu replicare asincron\u0103.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/dabcb7f6006520c4fec85fb925e8975e.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<p>\u00cen acela\u0219i timp, nu am putut stoca \u00eentreaga cantitate de date \u00een PostgreSQL \u0219i pentru noi viteza de lucru cu baza a fost important\u0103, a\u0219a c\u0103 am \u00eenceput s\u0103 shard-uim PostgreSQL la nivel de aplica\u021bie. Schema descris\u0103 mai sus este relativ convenabil\u0103 pentru acest lucru: la ad\u0103ugarea unui nou shard, este suficient s\u0103 actualiz\u0103m configura\u021bia PgBouncer \u0219i aplica\u021bia poate lucra imediat cu noul shard.<\/p>\n<h3>Fiabilitatea PgBouncer<\/h3>\n<p>Aceast\u0103 schem\u0103 a func\u021bionat p\u00e2n\u0103 c\u00e2nd singurul instan\u021b PgBouncer a c\u0103zut. Ne afl\u0103m \u00een AWS, unde toate instan\u021bele sunt rulate pe hardware care se defecteaz\u0103 periodic. \u00cen astfel de cazuri, instan\u021ba se mut\u0103 pur \u0219i simplu pe un nou hardware \u0219i continu\u0103 s\u0103 func\u021bioneze. Exact asta s-a \u00eent\u00e2mplat cu PgBouncer, \u00eens\u0103 acesta a devenit indisponibil. Ca rezultat al acestei defec\u021biuni, serviciul nostru a fost indisponibil timp de 25 de minute. AWS recomand\u0103 pentru astfel de situa\u021bii s\u0103 se utilizeze redundan\u021ba la nivel de utilizator, ceea ce nu a fost implementat la noi \u00een acel moment.<\/p>\n<p>Dup\u0103 aceasta, ne-am g\u00e2ndit serios la disponibilitatea PgBouncer \u0219i a clusterelor PostgreSQL, deoarece o situa\u021bie similar\u0103 ar putea s\u0103 se repete cu orice instan\u021b\u0103 din contul nostru AWS.<\/p>\n<p>Planul nostru de redundan\u021b\u0103 pentru PgBouncer a fost construit astfel: toate serverele aplica\u021biei se conecteaz\u0103 la Network Load Balancer, sub care se afl\u0103 doi PgBouncer. Fiecare PgBouncer se uit\u0103 c\u0103tre acelea\u0219i mastere PostgreSQL ale fiec\u0103rui shard. \u00cen cazul \u00een care instan\u021ba AWS ar c\u0103dea din nou, tot traficul va fi redirec\u021bionat prin cel\u0103lalt PgBouncer. Redundan\u021ba Network Load Balancer este asigurat\u0103 de AWS.<\/p>\n<p>Aceast\u0103 schem\u0103 permite ad\u0103ugarea f\u0103r\u0103 probleme a unor noi servere PgBouncer.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/2c1f1e7d9f7be4fdeb43858520d55e36.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<h2>Crearea unui cluster PostgreSQL rezistent la defec\u021biuni<\/h2>\n<p>\u00cen rezolvarea acestei probleme, am analizat diferite op\u021biuni: failover personalizat, repmgr, AWS RDS, Patroni.<\/p>\n<h3>Scripturi personalizate<\/h3>\n<p>Pot monitoriza activitatea masterului \u0219i, \u00een cazul c\u0103derii acestuia, pot promova replica la master \u0219i actualiza configura\u021bia PgBouncer.<\/p>\n<p>Avantajele acestei abord\u0103ri constau \u00een simplitatea maxim\u0103, deoarece scrie\u021bi scripturile singuri \u0219i \u00een\u021belege\u021bi exact cum func\u021bioneaz\u0103.<\/p>\n<p>Dezavantaje:<\/p>\n<ul>\n<li>Masterul ar fi putut s\u0103 nu fi murit; \u00een schimb, ar fi putut avea loc o defec\u021biune de re\u021bea. Failover-ul, f\u0103r\u0103 a \u0219ti asta, va promova replica la master, iar vechiul master va continua s\u0103 func\u021bioneze. Ca rezultat, vom avea dou\u0103 servere \u00een rol de master \u0219i nu vom \u0219ti pe care dintre ele se afl\u0103 ultimele date actualizate. Aceast\u0103 situa\u021bie este cunoscut\u0103 \u0219i sub numele de split-brain;<\/li>\n<li>Am r\u0103mas f\u0103r\u0103 replic\u0103. \u00cen configura\u021bia noastr\u0103, avem un master \u0219i o replic\u0103; dup\u0103 comutare, replica este promovat\u0103 la master, iar noi nu mai avem replici, astfel c\u0103 trebuie s\u0103 ad\u0103ug\u0103m manual o nou\u0103 replic\u0103;<\/li>\n<li>Este necesar un monitorizare suplimentar\u0103 a activit\u0103\u021bii failover-ului, av\u00e2nd \u00een vedere c\u0103 avem 12 sharde PostgreSQL, ceea ce \u00eenseamn\u0103 c\u0103 trebuie s\u0103 monitoriz\u0103m 12 clustere. C\u00e2nd num\u0103rul shardurilor cre\u0219te, trebuie s\u0103 nu uit\u0103m s\u0103 actualiz\u0103m \u0219i failover-ul.<\/li>\n<\/ul>\n<p>Un failover scris de m\u00e2n\u0103 pare foarte complex \u0219i necesit\u0103 suport neobi\u0219nuit. Cu un cluster PostgreSQL, aceasta va fi cea mai simpl\u0103 op\u021biune, dar nu se scaleaz\u0103, a\u0219a c\u0103 nu se potrive\u0219te pentru noi.<\/p>\n<h3>Repmgr<\/h3>\n<p>Replication Manager pentru clustere PostgreSQL, care poate gestiona func\u021bionarea clusterului PostgreSQL. Cu toate acestea, nu are failover automat \u201edin cutie\u201d, a\u0219a c\u0103 va trebui s\u0103 scriem propriul \u201ewrapper\u201d deasupra solu\u021biei existente. A\u0219adar, totul ar putea fi chiar mai complicat dec\u00e2t cu scripturile scrise de m\u00e2n\u0103, de aceea nu am \u00eencercat nici m\u0103car Repmgr.<\/p>\n<h3>AWS RDS<\/h3>\n<p>Suport\u0103 tot ce avem nevoie, poate face backup-uri \u0219i suport\u0103 pool-uri de conexiuni. Are comutare automat\u0103: c\u00e2nd masterul moare, replica devine noul master, iar AWS schimb\u0103 \u00eenregistrarea DNS la noul master, \u00een timp ce replicile pot fi \u00een zone diferite.<\/p>\n<p>Dezavantajele includ lipsa unor set\u0103ri fine. Un exemplu de set\u0103ri fine sunt restric\u021biile pentru conexiunile TCP pe instan\u021bele noastre, ceea ce, din p\u0103cate, nu poate fi realizat \u00een RDS:<\/p>\n<pre><code class=\"python\">net.ipv4.tcp_keepalive_time=10\nnet.ipv4.tcp_keepalive_intvl=1\nnet.ipv4.tcp_keepalive_probes=5\nnet.ipv4.tcp_retries2=3\n<\/code><\/pre>\n<p>\u00cen plus, pre\u021bul pentru AWS RDS este aproape de dou\u0103 ori mai mare dec\u00e2t pre\u021bul obi\u0219nuit al instan\u021bei, ceea ce a fost motivul principal pentru a renun\u021ba la aceast\u0103 solu\u021bie.<\/p>\n<h3>Patroni<\/h3>\n<p>Acesta este un \u0219ablon \u00een python pentru gestionarea PostgreSQL cu o documenta\u021bie bun\u0103, failover automat \u0219i cod surs\u0103 pe github.<\/p>\n<p>Avantajele Patroni:<\/p>\n<ul>\n<li>Fiecare parametru de configurare este descris, este clar cum func\u021bioneaz\u0103 fiecare;<\/li>\n<li>Failover-ul automat func\u021bioneaz\u0103 din cutie;<\/li>\n<li>Scris \u00een python, iar deoarece noi scriem mult \u00een python, ne va fi mai u\u0219or s\u0103 rezolv\u0103m problemele \u0219i, poate, chiar s\u0103 ajut\u0103m dezvoltarea proiectului;<\/li>\n<li>Gestioneaz\u0103 complet PostgreSQL, permite modificarea configura\u021biei imediat pe toate nodurile clusterului, iar dac\u0103 aplicarea noii configura\u021bii necesit\u0103 repornirea clusterului, se poate face din nou cu ajutorul Patroni.<\/li>\n<\/ul>\n<p>Dezavantaje:<\/p>\n<ul>\n<li>Din documenta\u021bie nu este clar cum s\u0103 lucr\u0103m corect cu PgBouncer. De\u0219i este greu de numit un dezavantaj, deoarece sarcina Patroni este de a gestiona PostgreSQL, iar cum se vor face conexiunile c\u0103tre Patroni \u2014 este deja problema noastr\u0103;<\/li>\n<li>Exist\u0103 pu\u021bine exemple de implementare a Patroni la volume mari, \u00een timp ce exist\u0103 multe exemple de implement\u0103ri de la zero.<\/li>\n<\/ul>\n<p>\u00cen concluzie, pentru a crea un cluster rezistent la defec\u021biuni, am ales exact Patroni.<\/p>\n<h2>Procesul de implementare a Patroni<\/h2>\n<p>P\u00e2n\u0103 la Patroni, aveam 12 sharduri PostgreSQL configurate cu un master \u0219i o replic\u0103 cu replicare asincron\u0103. Serverele aplica\u021biei se conectau la bazele de date prin intermediul Network Load Balancer-ului, care era \u00een spatele a dou\u0103 instan\u021be cu PgBouncer, urmate de toate serverele PostgreSQL.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/8e5350d2466311593e11add30d5b1bdc.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<p>Pentru a implementa Patroni, a trebuit s\u0103 alegem un magazin de configura\u021bie distribuit pentru cluster. Patroni func\u021bioneaz\u0103 cu sisteme distribuite de stocare a configura\u021biilor, cum ar fi etcd, Zookeeper, Consul. De fapt, avem un cluster Consul complet func\u021bional \u00een produc\u021bie, care lucreaz\u0103 \u00eempreun\u0103 cu Vault \u0219i mai mult nu \u00eel folosim. Un motiv excelent pentru a \u00eencepe s\u0103 folosim Consul pentru scopul s\u0103u.<\/p>\n<h3>Cum func\u021bioneaz\u0103 Patroni cu Consul<\/h3>\n<p>Avem un cluster Consul, care const\u0103 din trei noduri \u0219i un cluster Patroni, care are un lider \u0219i o replic\u0103 (\u00een Patroni, masterul se nume\u0219te lider al clusterului, iar slabe-urile sunt replici). Fiecare instan\u021b\u0103 a clusterului Patroni trimite constant c\u0103tre Consul informa\u021bii despre starea clusterului. Prin urmare, din Consul se poate afla \u00eentotdeauna configura\u021bia curent\u0103 a clusterului Patroni \u0219i cine este liderul \u00een acel moment.<\/p>\n<p><img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/3234594b363904424fdce64c9d77fca5.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<p>Pentru a conecta Patroni la Consul, este suficient s\u0103 studiem documenta\u021bia oficial\u0103, care men\u021bioneaz\u0103 c\u0103 trebuie s\u0103 specific\u0103m gazda \u00een format http sau https, \u00een func\u021bie de modul \u00een care lucr\u0103m cu Consul, \u0219i schema de conectare, op\u021bional:<\/p>\n<pre><code class=\"plaintext\">host: gazda:port pentru punctul de terminare Consul, \u00een format: http(s):\/\/gazda:port\nscheme: (op\u021bional) http sau https, implicit http<\/code><\/pre>\n<p>Pare simplu, dar aici apar capcane. Lucr\u0103m cu Consul printr-o conexiune securizat\u0103 prin https \u0219i configura\u021bia noastr\u0103 de conectare va ar\u0103ta astfel:<\/p>\n<pre><code class=\"python\">consul:\n  host: https:\/\/server.production.consul:8080 \n  verify: true\n  cacert: {{ consul_cacert }}\n  cert: {{ consul_cert }}\n  key: {{ consul_key }}<\/code><\/pre>\n<p>Dar asta nu func\u021bioneaz\u0103. La pornire, Patroni nu se poate conecta la Consul, deoarece \u00eencearc\u0103 totu\u0219i s\u0103 foloseasc\u0103 http.<\/p>\n<p>S\u0103 \u00een\u021belegem problema a ajutat codul surs\u0103 al Patroni. E bine c\u0103 este scris \u00een python. Se pare c\u0103 parametrul gazd\u0103 nu este analizat, iar protocolul trebuie specificat \u00een scheme. Iat\u0103 cum arat\u0103 un bloc de configura\u021bie func\u021bional pentru a lucra cu Consul la noi:<\/p>\n<pre><code class=\"python\">consul:\n  host: server.production.consul:8080\n  scheme: https\n  verify: true\n  cacert: {{ consul_cacert }}\n  cert: {{ consul_cert }}\n  key: {{ consul_key }}<\/code><\/pre>\n<h3>Consul-template<\/h3>\n<p>A\u0219adar, am ales un depozit pentru configura\u021bie. Acum trebuie s\u0103 \u00een\u021belegem cum va comuta PgBouncer configura\u021biile sale atunci c\u00e2nd liderul din clusterul Patroni se schimb\u0103. \u00cen documenta\u021bie nu exist\u0103 un r\u0103spuns pentru aceast\u0103 \u00eentrebare, deoarece nu este descris\u0103 \u00een general interac\u021biunea cu PgBouncer.<\/p>\n<p>\u00cen c\u0103utarea unei solu\u021bii, am g\u0103sit un articol (din p\u0103cate nu-mi amintesc numele), unde era men\u021bionat c\u0103 Consul-template a ajutat foarte mult \u00een leg\u0103tura dintre PgBouncer \u0219i Patroni. Aceasta ne-a stimulat s\u0103 explor\u0103m func\u021bionarea Consul-template.<\/p>\n<p>Se pare c\u0103 Consul-template monitorizeaz\u0103 constant configura\u021bia clusterului PostgreSQL \u00een Consul. La schimbarea liderului, acesta actualizeaz\u0103 configura\u021bia PgBouncer \u0219i trimite o comand\u0103 pentru a o re\u00eenc\u0103rca.<\/p>\n<p><img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/6cf92996a127bb6637ab81dc45fdd60a.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<p>Un mare avantaj al template-ului este c\u0103 acesta este stocat sub form\u0103 de cod, astfel \u00eenc\u00e2t, atunci c\u00e2nd ad\u0103ug\u0103m un nou shard, este suficient s\u0103 facem un nou commit \u0219i s\u0103 actualiz\u0103m template-ul automat, men\u021bin\u00e2nd principiul Infrastructure as Code.<\/p>\n<h3>Noua arhitectur\u0103 cu Patroni<\/h3>\n<p>\u00cen rezultat, am ob\u021binut o schem\u0103 de lucru de acest fel:<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/bf9a9eff675a26039e3f76b16c6cd713.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<p>Toate serverele aplica\u021biei se conecteaz\u0103 la balansor \u2192 \u00een spatele s\u0103u sunt dou\u0103 instan\u021be PgBouncer \u2192 pe fiecare instan\u021b\u0103 ruleaz\u0103 Consul-template, care monitorizeaz\u0103 starea fiec\u0103rui cluster Patroni \u0219i se asigur\u0103 de actualitatea configura\u021biei PgBouncer, care trimite cereri c\u0103tre liderul actual al fiec\u0103rui cluster.<\/p>\n<h3>Testare manual\u0103<\/h3>\n<p>Aceast\u0103 schem\u0103, \u00eenainte de a fi lansat\u0103 \u00een produc\u021bie, a fost testat\u0103 pe un mediu de testare mic \u0219i am verificat func\u021bionarea comut\u0103rii automate. Am deschis un tablou, am mutat un sticker \u0219i \u00een acel moment am \u201eucis\u201d liderul clusterului. \u00cen AWS, pentru aceasta, este suficient s\u0103 opre\u0219ti instan\u021ba prin consol\u0103.<\/p>\n<p><img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/d670fe373b774f1b52bfd8a8c3b53a21.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<p>Sticker-ul revenea \u00eenapoi \u00een 10-20 de secunde, dup\u0103 care \u00eencepea din nou s\u0103 se mi\u0219te normal. A\u0219adar, clusterul Patroni a reac\u021bionat corect: a schimbat liderul, a trimis informa\u021bia \u00een Consul, iar Consul-template a preluat imediat aceast\u0103 informa\u021bie, a \u00eenlocuit configura\u021bia PgBouncer \u0219i a trimis o comand\u0103 pentru reload.<\/p>\n<h2>Cum s\u0103 supravie\u021buie\u0219ti sub o sarcin\u0103 mare \u0219i s\u0103 men\u021bii un timp minim de nefunc\u021bionare?<\/h2>\n<p>Totul func\u021bioneaz\u0103 excelent! Dar apar \u00eentreb\u0103ri noi: Cum va func\u021biona sub o sarcin\u0103 mare? C\u00e2t de repede \u0219i \u00een siguran\u021b\u0103 putem implementa totul \u00een produc\u021bie?<\/p>\n<p>R\u0103spunsul la prima \u00eentrebare ne ajut\u0103 un mediu de testare, pe care \u00eel folosim pentru testarea de \u00eenc\u0103rcare. Acesta este complet identic cu mediul de produc\u021bie din punct de vedere arhitectural \u0219i are date de test generate, care sunt aproximativ egale ca volum cu cele din produc\u021bie. Decidem pur \u0219i simplu s\u0103 \u201eomor\u00e2m\u201d unul dintre masterele PostgreSQL \u00een timpul testului \u0219i s\u0103 vedem ce se \u00eent\u00e2mpl\u0103. Dar \u00eenainte de aceasta, este important s\u0103 verific\u0103m desf\u0103\u0219urarea automat\u0103, deoarece \u00een acest mediu avem mai multe sharduri PostgreSQL, a\u0219a c\u0103 vom ob\u021bine o testare excelent\u0103 a scripturilor de configurare \u00eenainte de produc\u021bie.<\/p>\n<p>Ambele sarcini par ambi\u021bioase, dar avem PostgreSQL 9.6. Poate ne actualiz\u0103m direct la 11.2?<\/p>\n<p>Decidem s\u0103 facem acest lucru \u00een 2 etape: mai \u00eent\u00e2i s\u0103 actualiz\u0103m versiunea la 11.2, apoi s\u0103 lans\u0103m Patroni.<\/p>\n<h3>Actualizarea PostgreSQL<\/h3>\n<p>Pentru o actualizare rapid\u0103 a versiunii PostgreSQL, este necesar s\u0103 folosi\u021bi op\u021biunea <b>-k<\/b>, care creeaz\u0103 leg\u0103turi hard pe disc \u0219i nu necesit\u0103 copierea datelor dumneavoastr\u0103. Pe bazele de date cu 300-400 GB, actualizarea dureaz\u0103 1 secund\u0103.<\/p>\n<p>Avem multe sharduri, a\u0219a c\u0103 actualizarea trebuie s\u0103 fie realizat\u0103 \u00een mod automat. Pentru aceasta, am scris un playbook Ansible, care execut\u0103 \u00eentregul proces de actualizare pentru noi:<\/p>\n<pre><code class=\"plaintext\">\/usr\/lib\/postgresql\/11\/bin\/pg_upgrade \n&lt;b&gt;--leg\u0103tur\u0103 &lt;\/b&gt;\n--old-datadir=&#039;&#039; --new-datadir=&#039;&#039; \n --old-bindir=&#039;&#039;  --new-bindir=&#039;&#039; \n --old-options=&#039; -c config_file=&#039; \n --new-options=&#039; -c config_file=&#039;<\/code><\/pre>\n<p>Aici este important de men\u021bionat c\u0103 \u00eenainte de a lansa upgrade-ul, trebuie s\u0103-l execut\u0103m cu parametru <b>\u2014check<\/b>, pentru a fi siguri de posibilitatea upgrade-ului. De asemenea, scriptul nostru face \u00eenlocuirea fi\u0219ierelor de configurare \u00een timpul upgrade-ului. Scriptul nostru a fost finalizat \u00een 30 de secunde, ceea ce este un rezultat excelent.<\/p>\n<h3>Lansarea Patroni<\/h3>\n<p>Pentru a rezolva a doua problem\u0103, este suficient s\u0103 ne uit\u0103m la configura\u021bia Patroni. \u00cen repository-ul oficial exist\u0103 un exemplu de configura\u021bie cu initdb, care este responsabil pentru ini\u021bializarea unei noi baze la prima lansare a Patroni. Dar, deoarece avem deja o baz\u0103 gata, am eliminat pur \u0219i simplu aceast\u0103 sec\u021biune din configura\u021bie.<\/p>\n<p>C\u00e2nd am \u00eenceput s\u0103 instal\u0103m Patroni pe un cluster PostgreSQL deja existent \u0219i s\u0103-l lans\u0103m, ne-am confruntat cu o nou\u0103 problem\u0103: ambele servere se lansau ca lider. Patroni nu \u0219tie nimic despre starea anterioar\u0103 a cluster-ului \u0219i \u00eencearc\u0103 s\u0103 porneasc\u0103 ambele servere ca dou\u0103 clustere separate cu acela\u0219i nume. Pentru a rezolva aceast\u0103 problem\u0103, este necesar s\u0103 \u0219tergem directorul cu date pe slave:<\/p>\n<pre><code class=\"plaintext\">rm -rf \/var\/lib\/postgresql\/<\/code><\/pre>\n<p><b>Aceasta trebuie s\u0103 fie f\u0103cut\u0103 doar pe slave!<\/b><\/p>\n<p>C\u00e2nd se conecteaz\u0103 o replic\u0103 curat\u0103, Patroni face un basebackup de la lider \u0219i \u00eel restabile\u0219te pe replic\u0103, apoi ajunge la starea actual\u0103 prin jurnalul wal.<\/p>\n<p>O alt\u0103 dificultate cu care ne-am confruntat este c\u0103 toate clusterele PostgreSQL sunt, \u00een mod implicit, numite main. C\u00e2nd fiecare cluster nu \u0219tie nimic despre altul, este \u00een regul\u0103. Dar c\u00e2nd dori\u021bi s\u0103 folosi\u021bi Patroni, toate clusterele trebuie s\u0103 aib\u0103 un nume unic. Solu\u021bia este s\u0103 schimba\u021bi numele clusterului \u00een configura\u021bia PostgreSQL.<\/p>\n<h3>Test de \u00eenc\u0103rcare<\/h3>\n<p>Am efectuat un test care imit\u0103 activitatea utilizatorilor pe tableau. C\u00e2nd \u00eenc\u0103rcarea a atins valoarea noastr\u0103 medie zilnic\u0103, am repetat exact acela\u0219i test \u0219i am oprit un instance cu liderul PostgreSQL. Failover-ul automat a func\u021bionat a\u0219a cum ne a\u0219teptam: Patroni a schimbat liderul, Sconsul-template a actualizat configura\u021bia PgBouncer \u0219i a trimis comanda de reload. Din graficele noastre \u00een Grafana, a fost vizibil c\u0103 au existat \u00eent\u00e2rzieri de 20-30 de secunde \u0219i un volum mic de erori de la serverele asociate cu conexiunea la baza de date. Aceasta este o situa\u021bie normal\u0103, astfel de valori sunt acceptabile pentru failover-ul nostru \u0219i cu siguran\u021b\u0103 sunt mai bune dec\u00e2t downtime-ul serviciului.<\/p>\n<h2>Iesirea Patroni \u00een produc\u021bie<\/h2>\n<p>\u00cen final, am ob\u021binut urm\u0103torul plan:<\/p>\n<ul>\n<li>Deploy-ul Sconsul-template pe serverele PgBouncer \u0219i lansarea;<\/li>\n<li>Actualizarea PostgreSQL la versiunea 11.2;<\/li>\n<li>Schimbarea numelui clusterului;<\/li>\n<li>Lansarea clusterului Patroni.<\/li>\n<\/ul>\n<p>\u00cen acest timp, schema noastr\u0103 permite realizarea primului punct practic \u00een orice moment, putem scoate pe r\u00e2nd fiecare PgBouncer din func\u021biune \u0219i efectua deploy-ul \u0219i lansarea consul-template. A\u0219a am procedat.<\/p>\n<p>Pentru o desf\u0103\u0219urare rapid\u0103, am folosit Ansible, deoarece toate playbook-urile le-am testat deja \u00een mediu de testare, iar timpul de execu\u021bie al scenariului complet a fost de la 1,5 la 2 minute pentru fiecare shard. Am putea s\u0103 desf\u0103\u0219ur\u0103m totul pe r\u00e2nd pe fiecare shard f\u0103r\u0103 a opri serviciul nostru, dar ar fi trebuit s\u0103 oprim fiecare PostgreSQL timp de c\u00e2teva minute. \u00cen acest caz, utilizatorii al c\u0103ror date sunt pe acest shard nu ar fi putut lucra \u00een mod normal \u00een acest timp, iar acest lucru pentru noi este inacceptabil.<\/p>\n<p>Solu\u021bia a fost un maintenance planificat, care se desf\u0103\u0219oar\u0103 la fiecare 3 luni. Acest interval este rezervat pentru lucr\u0103ri de \u00eentre\u021binere programate, c\u00e2nd oprim complet serviciul nostru \u0219i actualiz\u0103m instan\u021bele bazelor de date. Mai r\u0103m\u0103sese o s\u0103pt\u0103m\u00e2n\u0103 p\u00e2n\u0103 la urm\u0103torul interval \u0219i am decis s\u0103 a\u0219tept\u0103m \u0219i s\u0103 ne preg\u0103tim suplimentar. \u00cen timpul a\u0219tept\u0103rii, ne-am asigurat suplimentar: pentru fiecare shard PostgreSQL am ridicat c\u00e2te o replic\u0103 de rezerv\u0103 \u00een caz de e\u0219ec, pentru a p\u0103stra cele mai recente date, \u0219i am ad\u0103ugat c\u00e2te o nou\u0103 instan\u021b\u0103 pentru fiecare shard, care va deveni noua replic\u0103 \u00een clusterul Patroni, astfel \u00eenc\u00e2t s\u0103 nu execut\u0103m comanda pentru \u0219tergerea datelor. Toate acestea au ajutat la minimizarea riscurilor de eroare.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/29e5c5f50dbfebfe5665fa0aeb009728.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<p>Am repornit serviciul nostru, totul a func\u021bionat corespunz\u0103tor, utilizatorii au continuat s\u0103 lucreze, dar pe grafice am observat o \u00eenc\u0103rcare anormal de mare pe serverele Consul.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/af0eef9ac235706c0aac62d2e1ee179d.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<p>De ce nu am observat asta pe mediu de testare? Aceast\u0103 problem\u0103 ilustreaz\u0103 foarte bine necesitatea de a urma principiul Infrastructure as Code \u0219i de a dezvolta \u00eentreaga infrastructur\u0103, \u00eencep\u00e2nd cu mediile de testare \u0219i termin\u00e2nd cu production. Altfel, este foarte u\u0219or s\u0103 \u00eent\u00e2lne\u0219ti o problem\u0103 similar\u0103 cu cea pe care am avut-o noi. Ce s-a \u00eent\u00e2mplat? Consul a ap\u0103rut mai \u00eent\u00e2i pe production, iar apoi pe mediile de testare, iar \u00een final pe mediile de testare versiunea Consul era mai recent\u0103 dec\u00e2t pe production. Chiar \u00eentr-unul dintre release-uri a fost rezolvat\u0103 o scurgere de CPU c\u00e2nd se lucra cu consul-template. A\u0219adar, am actualizat Consul, rezolv\u00e2nd astfel problema.<\/p>\n<h3>Repornire cluster Patroni<\/h3>\n<p>Cu toate acestea, am \u00eent\u00e2mpinat o nou\u0103 problem\u0103, despre care nici nu b\u0103nuiai. C\u00e2nd actualiz\u0103m Consul, pur \u0219i simplu elimin\u0103m nodul Consul din cluster folosind comanda consul leave \u2192 Patroni se conecteaz\u0103 la un alt server Consul \u2192 totul func\u021bioneaz\u0103. Dar c\u00e2nd am ajuns la ultima instan\u021b\u0103 din clusterul Consul \u0219i i-am trimis comanda consul leave, toate clusterele Patroni s-au repornit, iar \u00een loguri am v\u0103zut urm\u0103toarea eroare:<\/p>\n<pre><code class=\"plaintext\">EROARE: get_cluster\n&Icirc;napoi la apelul recent:\n...\nRetryFailedError: &#039;Limita de re&icirc;ncercare a fost dep\u0103\u0219it\u0103&#039;\nEROARE: Eroare de comunicare cu DCS\n&lt;b&gt;LOG: sistemul de baze de date este oprit&lt;\/b&gt;<\/code><\/pre>\n<p>Clusterul Patroni nu a putut ob\u021bine informa\u021bii despre propriul cluster \u0219i s-a repornit.<\/p>\n<p>Pentru a g\u0103si o solu\u021bie, ne-am adresat autorilor Patroni printr-o problem\u0103 pe GitHub. Ace\u0219tia au propus \u00eembun\u0103t\u0103\u021biri ale fi\u0219ierelor noastre de configurare:<\/p>\n<pre><code class=\"python\">consul:\n consul.checks: []\nbootstrap:\n dcs:\n   retry_timeout: 8<\/code><\/pre>\n<p>Am reu\u0219it s\u0103 repet\u0103m problema pe mediu de testare \u0219i am testat acolo aceste set\u0103ri, dar, din p\u0103cate, ele nu au func\u021bionat.<\/p>\n<p>Problema r\u0103m\u00e2ne nerezolvat\u0103. Pl\u0103nuim s\u0103 \u00eencerc\u0103m urm\u0103toarele solu\u021bii:<\/p>\n<ul>\n<li>Utilizarea agentului Consul pe fiecare instan\u021b\u0103 a clusterei Patroni;<\/li>\n<li>Corectarea problemei \u00een cod.<\/li>\n<\/ul>\n<p>Ne este clar locul \u00een care apare eroarea: probabil, problema se afl\u0103 \u00een utilizarea timeout-ului implicit, care nu este suprascris prin fi\u0219ierul de configurare. La eliminarea ultimei instan\u021be Consul din cluster, \u00eentreg clusterul Consul se blocheaz\u0103 pentru mai mult de o secund\u0103, din acest motiv Patroni nu poate ob\u021bine starea clusterului \u0219i reporne\u0219te complet \u00eentregul cluster.<\/p>\n<p>Din fericire, nu am \u00eent\u00e2mpinat alte erori.<\/p>\n<h2>Sumar privind utilizarea Patroni<\/h2>\n<p>Dup\u0103 lansarea cu succes a Patroni, am ad\u0103ugat c\u00e2te o replic\u0103 suplimentar\u0103 \u00een fiecare cluster. Acum, \u00een fiecare cluster exist\u0103 o form\u0103 de cvorum: un lider \u0219i dou\u0103 replici, pentru a asigura protec\u021bie \u00een cazul unui split-brain la comutare.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/3bb4c0495fea274b04edd2e99b59eacb.png\" alt=\"Cluster PostgreSQL rezilient + Patroni. Experien\u021b\u0103 de implementare\" \/><\/p>\n<p>Pe produc\u021bie, Patroni func\u021bioneaz\u0103 de mai bine de trei luni. \u00cen acest timp, ne-a scos de multe ori din impas. Recent, \u00een AWS, liderul unuia dintre clustere a murit, failover-ul automat s-a activat \u0219i utilizatorii au continuat s\u0103 lucreze. Patroni \u0219i-a \u00eendeplinit sarcina principal\u0103.<\/p>\n<p><b>Un mic sumar al utiliz\u0103rii Patroni:<\/b><\/p>\n<ul>\n<li>U\u0219urin\u021ba de a schimba configura\u021bia. Este suficient s\u0103 schimbi configura\u021bia pe o instan\u021b\u0103 \u0219i aceasta se va aplica la \u00eentregul cluster. Dac\u0103 este necesar\u0103 repornirea pentru aplicarea noii configura\u021bii, Patroni va anun\u021ba acest lucru. Patroni poate reporni \u00eentregul cluster cu un singur comand\u0103, ceea ce este deosebit de convenabil.<\/li>\n<li>Failover-ul automat func\u021bioneaz\u0103 \u0219i ne-a salvat deja.<\/li>\n<li>Actualizarea PostgreSQL f\u0103r\u0103 downtime pentru aplica\u021bie. Este necesar mai \u00eent\u00e2i s\u0103 actualizezi replicile la noua versiune, apoi s\u0103 schimbi liderul \u00een clusterul Patroni \u0219i s\u0103 actualizezi vechiul lider. \u00cen timpul acestui proces se efectueaz\u0103 testarea necesar\u0103 a failover-ului automat.<\/li>\n<\/ul>\n<p>Sursa: <a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/miro\/blog\/457326\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043c\u044b \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u043a \u0432\u043e\u043f\u0440\u043e\u0441\u0443 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438 PostgreSQL, \u043f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0441\u0442\u0430\u043b\u043e \u0434\u043b\u044f \u043d\u0430\u0441 \u0432\u0430\u0436\u043d\u043e \u0438 \u0447\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c. \u0423 \u043d\u0430\u0441 \u0432\u044b\u0441\u043e\u043a\u043e\u043d\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441: 2,5 \u043c\u043b\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u043c\u0438\u0440\u0443, 50\u041a+ \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c. \u0421\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 Amazone \u0432 \u043e\u0434\u043d\u043e\u043c \u0440\u0435\u0433\u0438\u043e\u043d\u0435 \u0418\u0440\u043b\u0430\u043d\u0434\u0438\u0438: \u0432 \u0440\u0430\u0431\u043e\u0442\u0435 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e 100+ \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432, \u0438\u0437 \u043d\u0438\u0445 \u043f\u043e\u0447\u0442\u0438 50 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":26749,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35706","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043c\u044b \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u043a \u0432\u043e\u043f\u0440\u043e\u0441\u0443 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438 PostgreSQL, \u043f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0441\u0442\u0430\u043b\u043e \u0434\u043b\u044f \u043d\u0430\u0441 \u0432\u0430\u0436\u043d\u043e \u0438 \u0447\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0442\u0435\u0440 PostgreSQL + Patroni. \u041e\u043f\u044b\u0442 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043c\u044b \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u043a \u0432\u043e\u043f\u0440\u043e\u0441\u0443 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438 PostgreSQL, \u043f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0441\u0442\u0430\u043b\u043e \u0434\u043b\u044f \u043d\u0430\u0441 \u0432\u0430\u0436\u043d\u043e \u0438 \u0447\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:05:50+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2026-05-18T18:58:46+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Cluster PostgreSQL rezistent la erori + Patroni. Experien\u021ba implement\u0103rii | ProHoster","description":"\u00cen acest articol, voi explica cum am abordat problema rezilien\u021bei PostgreSQL, de ce a devenit important\u0103 pentru noi \u0219i ce am realizat \u00een final.","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0442\u0435\u0440 PostgreSQL + Patroni. \u041e\u043f\u044b\u0442 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f | ProHoster","og:description":"\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u043c\u044b \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u043a \u0432\u043e\u043f\u0440\u043e\u0441\u0443 \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438 PostgreSQL, \u043f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0441\u0442\u0430\u043b\u043e \u0434\u043b\u044f \u043d\u0430\u0441 \u0432\u0430\u0436\u043d\u043e \u0438 \u0447\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c.","og:url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:05:50+00:00","article:modified_time":"2026-05-18T18:58:46+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35706","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 00:26:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 13:51:06","updated":"2026-01-22 00:26:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/35706","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=35706"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/35706\/revisions"}],"predecessor-version":[{"id":172654,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/35706\/revisions\/172654"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media\/26749"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=35706"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=35706"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=35706"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}