{"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\/it\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya","title":{"rendered":"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>In questo articolo, parler\u00f2 di come abbiamo affrontato il problema della resilienza di PostgreSQL, perch\u00e9 \u00e8 diventato importante per noi e quali risultati abbiamo ottenuto.<\/p>\n<p>Gestiamo un servizio ad alta intensit\u00e0 di carico: 2,5 milioni di utenti in tutto il mondo, con oltre 50.000 utenti attivi ogni giorno. I server sono situati in Amazon in un'unica regione dell'Irlanda: sono sempre in funzione pi\u00f9 di 100 server, di cui quasi 50 dedicati a basi di dati.<\/p>\n<p>L'intero backend \u00e8 un grande applicativo monolitico stateful in Java, che mantiene una connessione websocket costante con il cliente. Quando pi\u00f9 utenti lavorano contemporaneamente su una bacheca, vedono tutti le modifiche in tempo reale, perch\u00e9 ogni cambiamento viene registrato nel database. Riceviamo circa 10.000 richieste al secondo ai nostri database. Durante i picchi di carico, in Redis scriviamo tra 80.000 e 100.000 richieste al secondo.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/443f85815b0560fade7db5b639942935.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><br \/>\n<a rel=\"nofollow\" name=\"habracut\"><\/a><\/p>\n<h2>Perch\u00e9 siamo passati da Redis a PostgreSQL<\/h2>\n<p>Inizialmente, il nostro servizio operava con Redis, un archivio key-value che memorizza tutti i dati in memoria. <a href=\"https:\/\/prohoster.info\/it\/server\/\">server<\/a>.<\/p>\n<p>Vantaggi di Redis:<\/p>\n<ol>\n<li>Alta velocit\u00e0 di risposta, poich\u00e9 tutto \u00e8 memorizzato nella memoria;<\/li>\n<li>Facilit\u00e0 di backup e replicazione.<\/li>\n<\/ol>\n<p>Svantaggi di Redis per noi:<\/p>\n<ol>\n<li>Non ci sono transazioni reali. Abbiamo cercato di simularle a livello della nostra applicazione. Sfortunatamente, non sempre ha funzionato bene e ha richiesto la scrittura di codice molto complesso.<\/li>\n<li>Il volume dei dati \u00e8 limitato dalla quantit\u00e0 di memoria. Aumentando la quantit\u00e0 di dati, la memoria crescer\u00e0 e, alla fine, ci imbatteremo nelle caratteristiche dell'istanza selezionata, il che su AWS richiede l'interruzione del nostro servizio per modificare il tipo di istanza.<\/li>\n<li>\u00c8 necessario mantenere costantemente un basso livello di latenza, poich\u00e9 abbiamo un numero molto elevato di richieste. Il nostro livello di latenza ottimale \u00e8 di 17-20 ms. A livelli di 30-40 ms, riceviamo risposte lente alle richieste della nostra applicazione e un degrado del servizio. Sfortunatamente, \u00e8 successo a settembre 2018, quando uno degli istanze con Redis ha ricevuto per qualche motivo una latenza doppia rispetto al normale. Per risolvere il problema, abbiamo interrotto il servizio a met\u00e0 giornata per una manutenzione straordinaria e sostituito l'istanza Redis problematica.<\/li>\n<li>\u00c8 facile avere incoerenza nei dati anche con piccoli errori nel codice e poi spendere molto tempo a scrivere codice per correggere questi dati.<\/li>\n<\/ol>\n<p>Abbiamo preso in considerazione gli svantaggi e abbiamo capito che era necessario migrare verso qualcosa di pi\u00f9 conveniente, con transazioni adeguate e minore dipendenza dalla latenza. Abbiamo condotto ricerche, analizzato molte opzioni e scelto PostgreSQL.<\/p>\n<p>Stiamo migrando verso il nuovo database da 1,5 anni e abbiamo trasferito solo una piccola parte dei dati, quindi ora stiamo lavorando contemporaneamente con Redis e PostgreSQL. Maggiori dettagli sulle fasi della migrazione e sul passaggio dei dati tra i database sono riportati in <a href=\"https:\/\/habr.com\/ru\/company\/miro\/blog\/437826\/\" rel=\"nofollow\">un articolo del mio collega<\/a>.<\/p>\n<p>Quando abbiamo iniziato a migrare, la nostra applicazione interagiva direttamente con il database e si collegava al master Redis e PostgreSQL. Il cluster PostgreSQL era composto da un master e una replica con replica asincrona. Questo \u00e8 come appariva lo schema di funzionamento con i database:<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/674dd77de4c8b48a946c9f64c0b2fdd1.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<h2>Implementazione di PgBouncer<\/h2>\n<p>Mentre ci trasferivamo, anche il prodotto si \u00e8 evoluto: il numero di utenti e di server che lavoravano con PostgreSQL \u00e8 aumentato, e abbiamo cominciato a sperimentare carenze di connessioni. PostgreSQL crea un processo separato per ogni connessione e consuma risorse. \u00c8 possibile aumentare il numero di connessioni solo fino a un certo punto, altrimenti si rischia di avere prestazioni non ottimali del DB. In una situazione simile, la scelta di un gestore di connessioni che si interponga tra l'applicazione e il database \u00e8 l'opzione migliore.<\/p>\n<p>Avevamo due opzioni per il gestore di connessioni: Pgpool e PgBouncer. Tuttavia, il primo non supporta la modalit\u00e0 di lavoro transazionale con il database, quindi abbiamo scelto PgBouncer.<\/p>\n<p>Abbiamo impostato il seguente schema di lavoro: la nostra applicazione si connette a un PgBouncer, dietro il quale ci sono i master di PostgreSQL, e dietro ogni master c'\u00e8 una replica con replica asincrona.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/dabcb7f6006520c4fec85fb925e8975e.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<p>Tuttavia, non potevamo memorizzare l'intero volume di dati in PostgreSQL e per noi era importante la velocit\u00e0 del lavoro con il database, quindi abbiamo iniziato a shardare PostgreSQL a livello applicativo. Lo schema descritto sopra \u00e8 relativamente comodo per questo: aggiungendo un nuovo shard, \u00e8 sufficiente aggiornare la configurazione di PgBouncer e l'applicazione pu\u00f2 subito lavorare con il nuovo shard.<\/p>\n<h3>Affidabilit\u00e0 di PgBouncer<\/h3>\n<p>Questo schema ha funzionato fino a quando l'unico istanza di PgBouncer non \u00e8 andata in down. Siamo su AWS, dove tutte le istanze sono eseguite su hardware che periodicamente pu\u00f2 guastarsi. In questi casi, l'istanza semplicemente si sposta su un nuovo hardware e riprende a funzionare. \u00c8 successo anche con PgBouncer, ma \u00e8 diventato inaccessibile. Come risultato di questo guasto, il nostro servizio \u00e8 stato inattivo per 25 minuti. AWS consiglia di utilizzare la ridondanza dal lato dell'utente per tali situazioni, ma noi non l'avevamo implementata in quel momento.<\/p>\n<p>Dopo ci\u00f2, abbiamo seriamente considerato l'affidabilit\u00e0 di PgBouncer e dei cluster PostgreSQL, poich\u00e9 una situazione del genere potrebbe ripetersi con qualsiasi istanza nel nostro account AWS.<\/p>\n<p>Abbiamo costruito lo schema di alta disponibilit\u00e0 per PgBouncer nel seguente modo: tutti i server applicativi fanno riferimento a un Network Load Balancer, dietro il quale si trovano due PgBouncer. Ognuno dei PgBouncer punta ai medesimi master PostgreSQL di ciascuno shard. In caso di ripetizione della situazione di inattivit\u00e0 di un'istanza AWS, tutto il traffico viene reindirizzato attraverso un altro PgBouncer. L'alta disponibilit\u00e0 del Network Load Balancer \u00e8 garantita da AWS.<\/p>\n<p>Questo schema consente di aggiungere nuovi server PgBouncer senza problemi.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/2c1f1e7d9f7be4fdeb43858520d55e36.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<h2>Creazione di un cluster PostgreSQL ad alta disponibilit\u00e0<\/h2>\n<p>Nella risoluzione di questo compito, abbiamo considerato diverse opzioni: failover personalizzato, repmgr, AWS RDS, Patroni.<\/p>\n<h3>Script personalizzati<\/h3>\n<p>Possono monitorare il funzionamento del master e, in caso di caduta, promuovere la replica a master e aggiornare la configurazione di PgBouncer.<\/p>\n<p>I vantaggi di questo approccio risiedono nella massima semplicit\u00e0, poich\u00e9 scrivete voi stessi gli script e capite esattamente come funzionano.<\/p>\n<p>Contro:<\/p>\n<ul>\n<li>Il master potrebbe non essere morto; invece, potrebbe essersi verificato un guasto di rete. Il failover, ignaro di ci\u00f2, promuover\u00e0 la replica a master, mentre il vecchio master continuer\u00e0 a funzionare. Di conseguenza, avremo due server in modalit\u00e0 master e non sapremo su quale di essi siano i dati pi\u00f9 recenti. Questa situazione \u00e8 anche chiamata split-brain.<\/li>\n<li>Siamo rimasti senza replica. Nella nostra configurazione, ci sono un master e una replica, e dopo il failover la replica viene promossa a master, quindi non abbiamo pi\u00f9 repliche e dobbiamo aggiungere manualmente una nuova replica.<\/li>\n<li>\u00c8 necessario un monitoraggio aggiuntivo del failover; abbiamo 12 shard PostgreSQL, quindi dobbiamo monitorare 12 cluster. Aumentando il numero di shard, non dimentichiamo di aggiornare il failover.<\/li>\n<\/ul>\n<p>Un failover personalizzato sembra molto complesso e richiede manutenzione non banale. Con un solo cluster PostgreSQL, sarebbe l'opzione pi\u00f9 semplice, ma non \u00e8 scalabile, quindi non \u00e8 adatta a noi.<\/p>\n<h3>Repmgr<\/h3>\n<p>Replication Manager per cluster PostgreSQL, che gestisce il funzionamento del cluster PostgreSQL. Tuttavia, non dispone di failover automatico \u201cdi serie\u201d, quindi sar\u00e0 necessario scrivere un proprio \u201cwrapper\u201d sopra la soluzione esistente. Quindi, potrebbe risultare anche pi\u00f9 complesso rispetto a script scritti da zero, motivo per cui non abbiamo nemmeno provato Repmgr.<\/p>\n<h3>AWS RDS<\/h3>\n<p>Supporta tutto il necessario per noi, \u00e8 in grado di fare backup e gestisce un pool di connessioni. Ha uno switch automatico: alla morte del master, la replica diventa il nuovo master, e AWS cambia il record DNS al nuovo master, mentre le repliche possono trovarsi in diverse AZ.<\/p>\n<p>Tra i lati negativi si pu\u00f2 citare l'assenza di impostazioni dettagliate. Ad esempio, impostazioni dettagliate: sulle nostre istanze ci sono limitazioni per le connessioni TCP, cosa che purtroppo non possiamo fare in 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>Inoltre, il prezzo di AWS RDS \u00e8 quasi il doppio del prezzo normale delle istanze, che \u00e8 stata la principale causa del rifiuto di questa soluzione.<\/p>\n<h3>Patroni<\/h3>\n<p>\u00c8 un template in Python per gestire PostgreSQL con una buona documentazione, failover automatico e codice sorgente su GitHub.<\/p>\n<p>Vantaggi di Patroni:<\/p>\n<ul>\n<li>Ogni parametro di configurazione \u00e8 dettagliato, rendendo chiaro come funziona ogni parte.<\/li>\n<li>Il failover automatico funziona out-of-the-box.<\/li>\n<li>Scritto in Python, e poich\u00e9 anche noi scriviamo molto in Python, sar\u00e0 pi\u00f9 facile risolvere problemi e, forse, anche aiutare lo sviluppo del progetto.<\/li>\n<li>Gestisce completamente PostgreSQL, permette di modificare la configurazione su tutti i nodi del cluster e, se \u00e8 necessario riavviare il cluster per applicare la nuova configurazione, questo pu\u00f2 essere fatto ancora con Patroni.<\/li>\n<\/ul>\n<p>Contro:<\/p>\n<ul>\n<li>Dalla documentazione non \u00e8 chiaro come lavorare correttamente con PgBouncer. Sebbene non sia facile definire questo un difetto, perch\u00e9 il compito di Patroni \u00e8 gestire PostgreSQL, mentre gestire come avvengono le connessioni a Patroni \u00e8 gi\u00e0 un nostro problema.<\/li>\n<li>Ci sono pochi esempi di implementazione di Patroni su larga scala, mentre ci sono molti esempi di implementazione da zero.<\/li>\n<\/ul>\n<p>In definitiva, per creare un cluster ad alta disponibilit\u00e0 abbiamo scelto proprio Patroni.<\/p>\n<h2>Il processo di implementazione di Patroni.<\/h2>\n<p>Prima di Patroni avevamo 12 shard di PostgreSQL in una configurazione con un master e una replica con replica asincrona. I server delle applicazioni si collegavano ai database tramite un Network Load Balancer, dietro al quale c'erano due istanze con PgBouncer, e dietro di essi si trovavano tutti i server PostgreSQL.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/8e5350d2466311593e11add30d5b1bdc.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<p>Per implementare Patroni, abbiamo dovuto scegliere uno storage distribuito per la configurazione del cluster. Patroni funziona con sistemi distribuiti di storage della configurazione, come etcd, Zookeeper e Consul. Abbiamo infatti un cluster Consul completamente operativo in produzione, che lavora in sinergia con Vault e non lo utilizziamo in altro modo. \u00c8 un'ottima occasione per iniziare a usare Consul come previsto.<\/p>\n<h3>Come funziona Patroni con Consul<\/h3>\n<p>Abbiamo un cluster Consul composto da tre nodi e un cluster Patroni, costituito da un leader e da repliche (in Patroni, il master \u00e8 chiamato leader del cluster e gli slave sono repliche). Ogni istanza del cluster Patroni invia continuamente a Consul informazioni sullo stato del cluster. Pertanto, da Consul \u00e8 sempre possibile conoscere la configurazione attuale del cluster Patroni e chi \u00e8 il leader in quel momento.<\/p>\n<p><img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/3234594b363904424fdce64c9d77fca5.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<p>Per connettere Patroni a Consul, \u00e8 sufficiente consultare la documentazione ufficiale, che specifica che \u00e8 necessario indicare l'host nel formato http o https a seconda di come lavoriamo con Consul, e lo schema di connessione, opzionalmente:<\/p>\n<pre><code class=\"plaintext\">host: l'host:port per il punto finale di Consul, nel formato: http(s):\/\/host:port\nschema: (opzionale) http o https, predefinito a http<\/code><\/pre>\n<p>Sembra semplice, ma qui iniziano le insidie. Con Consul lavoriamo tramite una connessione sicura https e la nostra configurazione di connessione sar\u00e0 simile a questa:<\/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>Ma cos\u00ec non funziona. All'avvio, Patroni non riesce a connettersi a Consul perch\u00e9 continua a tentare di utilizzare http.<\/p>\n<p>Comprendere il problema \u00e8 stato possibile grazie al codice sorgente di Patroni. \u00c8 un bene che sia scritto in Python. Risulta che il parametro host non venga elaborato e il protocollo debba essere specificato in scheme. Ecco come appare un blocco di configurazione funzionante per l'uso con Consul:<\/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>Quindi, abbiamo scelto un archivio per la configurazione. Ora \u00e8 necessario capire come PgBouncer cambier\u00e0 la sua configurazione al cambiamento del leader nel cluster di Patroni. Nella documentazione non c'\u00e8 una risposta a questa domanda, poich\u00e9 in generale non viene descritta l'interazione con PgBouncer.<\/p>\n<p>Nella ricerca di una soluzione, abbiamo trovato un articolo (purtroppo non ricordo il titolo) che affermava che Consul-template fosse molto utile nell'integrazione tra PgBouncer e Patroni. Questo ci ha spinto ad esplorare il funzionamento di Consul-template.<\/p>\n<p>Si \u00e8 scoperto che il Consul-template monitora continuamente la configurazione del cluster PostgreSQL su Consul. Quando cambia il leader, aggiorna la configurazione di PgBouncer e invia il comando per il suo riavvio.<\/p>\n<p><img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/6cf92996a127bb6637ab81dc45fdd60a.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<p>Un grande vantaggio del template \u00e8 che \u00e8 memorizzato come codice, quindi quando si aggiunge un nuovo shard, \u00e8 sufficiente effettuare un nuovo commit e aggiornare automaticamente il template, mantenendo il principio dell'infrastruttura come codice.<\/p>\n<h3>Nuova architettura con Patroni<\/h3>\n<p>Di conseguenza, abbiamo ottenuto questo schema di lavoro:<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/bf9a9eff675a26039e3f76b16c6cd713.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<p>Tutti i server dell'applicazione si collegano al bilanciatore \u2192 dietro di esso ci sono due istanze di PgBouncer \u2192 in ogni istanza \u00e8 in esecuzione Consul-template, che monitora lo stato di ogni cluster Patroni e verifica la validit\u00e0 della configurazione di PgBouncer, che indirizza le richieste al leader attuale di ogni cluster.<\/p>\n<h3>Test manuale<\/h3>\n<p>Prima di passare alla produzione, abbiamo eseguito questo schema in un piccolo ambiente di test e abbiamo verificato il funzionamento del passaggio automatico. Abbiamo aperto la bacheca, spostato un adesivo e in quel momento 'abbiamo ucciso' il leader del cluster. In AWS, per fare questo, \u00e8 sufficiente spegnere l'istanza tramite la console.<\/p>\n<p><img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/d670fe373b774f1b52bfd8a8c3b53a21.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<p>L'adesivo tornava indietro per 10-20 secondi e poi iniziava a muoversi normalmente. Questo significa che il cluster Patroni ha funzionato correttamente: ha cambiato leader, ha inviato informazioni a Consul, e il template Consul ha subito acquisito queste informazioni, aggiornando la configurazione di PgBouncer e inviando il comando di reload.<\/p>\n<h2>Come sopravvivere a carichi elevati e mantenere un downtime minimo?<\/h2>\n<p>Tutto funziona alla grande! Ma sorgono nuove domande: come funzioner\u00e0 sotto carico elevato? Come distribuire tutto in produzione in modo rapido e sicuro?<\/p>\n<p>Per rispondere alla prima domanda, ci aiuta un ambiente di test in cui eseguiamo test di carico. \u00c8 completamente identico alla produzione per architettura e dispone di dati di test generati, che hanno un volume approssimativamente uguale alla produzione. Decidiamo semplicemente di 'uccidere' uno dei master PostgreSQL durante il test e vedere cosa succede. Ma prima \u00e8 importante verificare il rollout automatico, poich\u00e9 in questo ambiente abbiamo diversi shard PostgreSQL, quindi avremo un ottimo test degli script di configurazione prima della produzione.<\/p>\n<p>Entrambi i compiti sembrano ambiziosi, ma abbiamo PostgreSQL 9.6. Forse aggiorniamo subito alla 11.2?<\/p>\n<p>Ci proponiamo di farlo in 2 fasi: prima aggiornare la versione a 11.2, poi avviare Patroni.<\/p>\n<h3>Aggiornamento di PostgreSQL<\/h3>\n<p>Per un aggiornamento rapido della versione di PostgreSQL \u00e8 necessario utilizzare l\u2019opzione <b>-k<\/b>, che crea hard link sul disco ed elimina la necessit\u00e0 di copiare i tuoi dati. Su database da 300-400 GB, l'aggiornamento richiede 1 secondo.<\/p>\n<p>Abbiamo molti shard, quindi l'aggiornamento deve essere fatto in modo automatico. A tal fine, abbiamo scritto un playbook Ansible che esegue l'intero processo di aggiornamento per noi:<\/p>\n<pre><code class=\"plaintext\">\/usr\/lib\/postgresql\/11\/bin\/pg_upgrade \n&lt;b&gt;--link &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>\u00c8 importante notare che prima di avviare l'aggiornamento, \u00e8 necessario eseguirlo con il parametro <b>&#8212;check<\/b>, per essere certi della possibilit\u00e0 di aggiornamento. Inoltre, il nostro script fa il cambio delle configurazioni durante l'aggiornamento. Il nostro script \u00e8 stato eseguito in 30 secondi, un ottimo risultato.<\/p>\n<h3>Avvio di Patroni<\/h3>\n<p>Per risolvere il secondo problema, basta dare un'occhiata alla configurazione di Patroni. Nel repository ufficiale c'\u00e8 un esempio di configurazione con initdb, che si occupa di inizializzare un nuovo database al primo avvio di Patroni. Ma poich\u00e9 abbiamo gi\u00e0 un database pronto, abbiamo semplicemente rimosso questa sezione dalla configurazione.<\/p>\n<p>Quando abbiamo iniziato a installare Patroni su un cluster PostgreSQL esistente e ad avviarlo, ci siamo imbattuti in un nuovo problema: entrambi i server si avviavano come leader. Patroni non conosce lo stato precedente del cluster e cerca di avviare entrambi i server come due cluster separati con lo stesso nome. Per risolvere questo problema, \u00e8 necessario eliminare la directory dei dati sul server secondario:<\/p>\n<pre><code class=\"plaintext\">rm -rf \/var\/lib\/postgresql\/<\/code><\/pre>\n<p><b>Questo deve essere fatto solo sul server secondario!<\/b><\/p>\n<p>Quando si connette una replica pulita, Patroni esegue il basebackup del leader e lo ripristina sulla replica, quindi recupera lo stato attuale attraverso i log WAL.<\/p>\n<p>Un'altra difficolt\u00e0 che abbiamo incontrato \u00e8 che tutti i cluster PostgreSQL sono chiamati main per impostazione predefinita. Quando ogni cluster non sa nulla dell'altro, va bene. Ma quando si desidera utilizzare Patroni, tutti i cluster devono avere un nome unico. La soluzione \u00e8 cambiare il nome del cluster nella configurazione di PostgreSQL.<\/p>\n<h3>Test di carico<\/h3>\n<p>Abbiamo avviato un test che simula l'attivit\u00e0 degli utenti sui server. Quando il carico ha raggiunto la nostra media giornaliera, abbiamo ripetuto esattamente lo stesso test, disattivando un'istanza con leader PostgreSQL. Il failover automatico ha funzionato come previsto: Patroni ha cambiato leader, Consul-template ha aggiornato la configurazione di PgBouncer e ha inviato il comando per il reload. Dai nostri grafici in Grafana si vedeva che c'erano ritardi di 20-30 secondi e un piccolo numero di errori dai server, legati alla connessione al database. Questa \u00e8 una situazione normale, tali valori sono accettabili per il nostro failover e sono sicuramente migliori di un downtime del servizio.<\/p>\n<h2>Output di Patroni in produzione<\/h2>\n<p>Alla fine, abbiamo ottenuto il seguente piano:<\/p>\n<ul>\n<li>Deployment di Consul-template sui server PgBouncer e avvio;<\/li>\n<li>Aggiornamenti di PostgreSQL alla versione 11.2;<\/li>\n<li>Cambio del nome del cluster;<\/li>\n<li>Avvio del cluster Patroni.<\/li>\n<\/ul>\n<p>In questo modo, il nostro schema consente di eseguire il primo punto praticamente in qualsiasi momento, possiamo rimuovere ogni PgBouncer a turno e procedere con il deployment e l'avvio di consul-template. E cos\u00ec abbiamo fatto.<\/p>\n<p>Per una rapida implementazione, abbiamo utilizzato Ansible, poich\u00e9 avevamo gi\u00e0 testato tutti i playbook in un ambiente di test, e il tempo di esecuzione dell'intero scenario variava da 1,5 a 2 minuti per ogni shard. Avevamo la possibilit\u00e0 di rilasciarli uno dopo l'altro per ogni shard senza interrompere il nostro servizio, ma avremmo dovuto spegnere brevemente ciascun PostgreSQL. In tal caso, gli utenti i cui dati erano su quel shard non sarebbero stati in grado di lavorare correttamente in quel momento, il che \u00e8 inaccettabile per noi.<\/p>\n<p>La soluzione a questa situazione \u00e8 stata una manutenzione programmata, che si tiene ogni 3 mesi. Questo \u00e8 un intervallo per lavori pianificati, durante il quale spegniamo completamente il nostro servizio e aggiorniamo le istanze dei database. Una settimana prima della prossima finestra, abbiamo deciso di aspettare e prepararci ulteriormente. Durante il periodo di attesa, abbiamo preso ulteriori precauzioni: per ogni shard PostgreSQL abbiamo attivato una replica di backup in caso di guasti, per mantenere i dati pi\u00f9 recenti, e abbiamo aggiunto una nuova istanza per ciascuno shard, che diventer\u00e0 la nuova replica nel cluster Patroni, evitando cos\u00ec di eseguire il comando per eliminare i dati. Tutto ci\u00f2 ha contribuito a ridurre al minimo il rischio di errore.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/29e5c5f50dbfebfe5665fa0aeb009728.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<p>Abbiamo riavviato il nostro servizio, tutto ha funzionato come previsto, gli utenti hanno continuato a lavorare, ma nei grafici abbiamo notato un carico anomalo sui server Consul.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/af0eef9ac235706c0aac62d2e1ee179d.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<p>Perch\u00e9 non abbiamo visto questo nell'ambiente di test? Questo problema illustra chiaramente la necessit\u00e0 di seguire il principio di Infrastructure as code e di migliorare tutta l'infrastruttura, partendo dagli ambienti di test fino alla produzione. Altrimenti, \u00e8 molto facile imbattersi in un problema come quello che abbiamo avuto. Cosa \u00e8 successo? Consul \u00e8 stato inizialmente implementato in produzione e poi negli ambienti di test; alla fine, la versione di Consul negli ambienti di test era superiore a quella in produzione. Proprio in uno degli aggiornamenti \u00e8 stata risolta una perdita di CPU durante l'uso di consul-template. Pertanto, abbiamo semplicemente aggiornato Consul, risolvendo cos\u00ec il problema.<\/p>\n<h3>Riavviare il cluster Patroni<\/h3>\n<p>Tuttavia, abbiamo riscontrato un nuovo problema di cui non sospettavamo nemmeno. Durante l'aggiornamento di Consul, rimuoviamo semplicemente il nodo Consul dal cluster con il comando consul leave \u2192 Patroni si collega a un altro server Consul \u2192 tutto funziona. Ma quando siamo arrivati all'ultimo nodo del cluster Consul e abbiamo inviato il comando consul leave, tutti i cluster Patroni si sono semplicemente riavviati e nei log abbiamo visto il seguente errore:<\/p>\n<pre><code class=\"plaintext\">ERRORE: get_cluster\nTraccia (chiamata pi&ugrave; recente in alto):\n...\nRetryFailedError: &#039;Scadenza di ripetizione superata&#039;\nERRORE: Errore nella comunicazione con DCS\n&lt;b&gt;LOG: il sistema del database &egrave; stato chiuso&lt;\/b&gt;<\/code><\/pre>\n<p>Il cluster Patroni non \u00e8 riuscito a ottenere informazioni sul proprio cluster ed \u00e8 stato riavviato.<\/p>\n<p>Per cercare una soluzione, ci siamo rivolti agli autori di Patroni tramite issue su GitHub. Hanno suggerito di migliorare i nostri file di configurazione:<\/p>\n<pre><code class=\"python\">consul:\n consul.checks: []\nbootstrap:\n dcs:\n   retry_timeout: 8<\/code><\/pre>\n<p>Siamo riusciti a riprodurre il problema in un ambiente di test e abbiamo testato questi parametri, ma, sfortunatamente, non hanno funzionato.<\/p>\n<p>Il problema rimane irrisolto. Prevediamo di provare le seguenti opzioni per risolverlo:<\/p>\n<ul>\n<li>Utilizzare il Consul-agent su ogni istanza del cluster Patroni;<\/li>\n<li>Correggere il problema nel codice.<\/li>\n<\/ul>\n<p>Ci \u00e8 chiaro il luogo di provenienza dell'errore: probabilmente, il problema \u00e8 nell'uso del timeout predefinito, che non viene sovrascritto dal file di configurazione. Quando si rimuove l'ultimo server Consul dal cluster, si verifica un blocco dell'intero cluster Consul, che dura pi\u00f9 di un secondo, impedendo cos\u00ec a Patroni di ottenere lo stato del cluster e costringendo il riavvio completo dell'intero cluster.<\/p>\n<p>Fortunatamente, non abbiamo riscontrato ulteriori errori.<\/p>\n<h2>Sintesi dell'utilizzo di Patroni<\/h2>\n<p>Dopo il successo del lancio di Patroni, abbiamo aggiunto un'ulteriore replica in ogni cluster. Ora, in ogni cluster esiste una sorta di quorum: un leader e due repliche, per una maggiore sicurezza in caso di split-brain durante il failover.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/3bb4c0495fea274b04edd2e99b59eacb.png\" alt=\"Cluster PostgreSQL ad alta disponibilit\u00e0 + Patroni. Esperienza di implementazione\" \/><\/p>\n<p>In produzione, Patroni \u00e8 attivo da oltre tre mesi. Durante questo periodo, ci ha gi\u00e0 salvati. Recentemente, in AWS, il leader di uno dei cluster \u00e8 andato offline, il failover automatico ha funzionato e gli utenti hanno potuto continuare a lavorare. Patroni ha svolto il suo compito principale.<\/p>\n<p><b>Un breve riepilogo dell'utilizzo di Patroni:<\/b><\/p>\n<ul>\n<li>Comodit\u00e0 nel cambiare la configurazione. \u00c8 sufficiente modificare la configurazione su un'istanza e questa si propagher\u00e0 a tutto il cluster. Se \u00e8 necessario un riavvio per applicare la nuova configurazione, Patroni lo segnaler\u00e0. Patroni pu\u00f2 riavviare l'intero cluster con un solo comando, il che \u00e8 molto comodo.<\/li>\n<li>Il failover automatico funziona e ci ha gi\u00e0 salvati.<\/li>\n<li>Aggiornamento di PostgreSQL senza downtime per l'applicazione. \u00c8 necessario aggiornare prima le repliche alla nuova versione, poi cambiare il leader nel cluster Patroni e aggiornare il vecchio leader. Durante questo procedimento, avviene il necessario test del failover automatico.<\/li>\n<\/ul>\n<p>Fonte: <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 4.9.10 - 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. \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\" \/>\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\/it\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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. \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\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/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 resiliente + Patroni. Esperienza di implementazione | ProHoster","description":"In questo articolo parler\u00f2 di come abbiamo affrontato la questione della resilienza di PostgreSQL, perch\u00e9 \u00e8 diventata importante per noi e quale \u00e8 stato il risultato finale. Gestiamo un servizio ad alta domanda: 2,5 milioni di utenti in tutto il mondo, oltre 50.000 utenti attivi ogni giorno. I server si trovano in Amazon in un singolo regione in Irlanda: sono attivi costantemente pi\u00f9 di 100 diversi server, di cui quasi 50.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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. \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","og:url":"https:\/\/prohoster.info\/it\/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"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35706","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=35706"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35706\/revisions"}],"predecessor-version":[{"id":172654,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35706\/revisions\/172654"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/26749"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=35706"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=35706"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=35706"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}