{"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\/fr\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya","title":{"rendered":"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d'impl\u00e9mentation","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Dans cet article, je vais expliquer comment nous avons abord\u00e9 la question de la r\u00e9silience de PostgreSQL, pourquoi cela est devenu important pour nous et ce que nous avons finalement r\u00e9alis\u00e9.<\/p>\n<p>Nous avons un service \u00e0 fort trafic : 2,5 millions d'utilisateurs \u00e0 travers le monde, plus de 50 000 utilisateurs actifs chaque jour. Les serveurs sont h\u00e9berg\u00e9s sur Amazon dans une seule r\u00e9gion en Irlande : nous avons en fonctionnement plus de 100 serveurs diff\u00e9rents, dont pr\u00e8s de 50 avec des bases de donn\u00e9es.<\/p>\n<p>L'int\u00e9gralit\u00e9 de notre backend est une grande application monolithique stateful en Java, qui maintient une connexion websocket permanente avec le client. Lorsque plusieurs utilisateurs travaillent simultan\u00e9ment sur un m\u00eame tableau, ils voient tous les changements en temps r\u00e9el, car chaque changement est enregistr\u00e9 dans la base de donn\u00e9es. Nous traitons environ 10 000 requ\u00eates par seconde sur nos bases. En p\u00e9riode de pointe, nous \u00e9crivons entre 80 000 et 100 000 requ\u00eates par seconde dans Redis.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/443f85815b0560fade7db5b639942935.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><br \/>\n<a rel=\"nofollow\" name=\"habracut\"><\/a><\/p>\n<h2>Pourquoi nous sommes pass\u00e9s de Redis \u00e0 PostgreSQL<\/h2>\n<p>Au d\u00e9part, notre service fonctionnait avec Redis, un magasin de type key-value qui stocke toutes les donn\u00e9es en m\u00e9moire vive. <a href=\"https:\/\/prohoster.info\/fr\/server\/\">de serveurs<\/a>.<\/p>\n<p>Avantages de Redis :<\/p>\n<ol>\n<li>Haute vitesse de r\u00e9ponse, car tout est stock\u00e9 en m\u00e9moire ;<\/li>\n<li>Facilit\u00e9 de sauvegarde et de r\u00e9plication.<\/li>\n<\/ol>\n<p>Inconv\u00e9nients de Redis pour nous :<\/p>\n<ol>\n<li>Pas de v\u00e9ritables transactions. Nous avons tent\u00e9 de les simuler au niveau de notre application. Malheureusement, ce n'\u00e9tait pas toujours efficace et cela n\u00e9cessitait d'\u00e9crire un code tr\u00e8s complexe.<\/li>\n<li>Le volume de donn\u00e9es est limit\u00e9 par la quantit\u00e9 de m\u00e9moire. En augmentant la quantit\u00e9 de donn\u00e9es, la m\u00e9moire va cro\u00eetre, et finalement, nous atteindrons les caract\u00e9ristiques de l'instance choisie, ce qui dans AWS n\u00e9cessite de stopper notre service pour changer le type d'instance.<\/li>\n<li>Il est imp\u00e9ratif de maintenir un niveau de latence bas, car nous avons un tr\u00e8s grand nombre de requ\u00eates. Le niveau de latence optimal pour nous est de 17 \u00e0 20 ms. Avec un niveau de 30 \u00e0 40 ms, nous obtenons des r\u00e9ponses tardives aux requ\u00eates de notre application et une d\u00e9gradation du service. Malheureusement, cela nous est arriv\u00e9 en septembre 2018, lorsque l'une des instances avec Redis a inexplicablement connu une latence deux fois plus \u00e9lev\u00e9e que la normale. Pour r\u00e9soudre le probl\u00e8me, nous avons arr\u00eat\u00e9 le service au milieu de la journ\u00e9e pour une maintenance impr\u00e9vue et remplac\u00e9 l'instance Redis d\u00e9faillante.<\/li>\n<li>Il est facile de rencontrer des incoh\u00e9rences de donn\u00e9es m\u00eame avec des erreurs mineures dans le code, et ensuite de passer beaucoup de temps \u00e0 \u00e9crire du code pour corriger ces donn\u00e9es.<\/li>\n<\/ol>\n<p>Nous avons pris en compte les inconv\u00e9nients et r\u00e9alis\u00e9 qu'il \u00e9tait n\u00e9cessaire de passer \u00e0 une solution plus adapt\u00e9e, avec des transactions normales et une moindre d\u00e9pendance \u00e0 la latence. Nous avons men\u00e9 une \u00e9tude, analys\u00e9 de nombreuses options et choisi PostgreSQL.<\/p>\n<p>Nous migrons vers la nouvelle base de donn\u00e9es depuis d\u00e9j\u00e0 1,5 an et n'avons transf\u00e9r\u00e9 qu'une petite partie des donn\u00e9es, c'est pourquoi nous travaillons actuellement avec Redis et PostgreSQL en parall\u00e8le. Plus de d\u00e9tails sur les \u00e9tapes de la migration et le basculement des donn\u00e9es entre les bases de donn\u00e9es sont d\u00e9crits dans <a href=\"https:\/\/habr.com\/ru\/company\/miro\/blog\/437826\/\" rel=\"nofollow\">un article de mon coll\u00e8gue<\/a>.<\/p>\n<p>Lorsque nous avons commenc\u00e9 la migration, notre application interagissait directement avec la base de donn\u00e9es en se connectant \u00e0 Redis et PostgreSQL. Le cluster PostgreSQL \u00e9tait compos\u00e9 d'un ma\u00eetre et d'une r\u00e9plique avec r\u00e9plication asynchrone. Voici \u00e0 quoi ressemblait le sch\u00e9ma de fonctionnement avec les bases :<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/674dd77de4c8b48a946c9f64c0b2fdd1.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<h2>Mise en \u0153uvre de PgBouncer<\/h2>\n<p>Pendant que nous migrions, le produit \u00e9voluait \u00e9galement : le nombre d'utilisateurs et de serveurs utilisant PostgreSQL augmentait, et nous avons commenc\u00e9 \u00e0 manquer de connexions. PostgreSQL cr\u00e9e un processus distinct pour chaque connexion, consommant des ressources. On peut augmenter le nombre de connexions jusqu'\u00e0 un certain point, sinon il existe un risque de performances sous-optimales de la base de donn\u00e9es. La meilleure solution dans cette situation est de choisir un gestionnaire de connexions qui se positionne devant la base.<\/p>\n<p>Nous avions deux options pour le gestionnaire de connexions : Pgpool et PgBouncer. Cependant, le premier ne prend pas en charge le mode de travail transactionnel avec la base, donc nous avons choisi PgBouncer.<\/p>\n<p>Nous avons configur\u00e9 le sch\u00e9ma suivant : notre application se connecte \u00e0 un PgBouncer, derri\u00e8re lequel se trouvent les ma\u00eetres PostgreSQL, et derri\u00e8re chaque ma\u00eetre se trouve une r\u00e9plique avec r\u00e9plication asynchrone.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/dabcb7f6006520c4fec85fb925e8975e.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<p>Dans le m\u00eame temps, nous ne pouvions pas stocker tout le volume de donn\u00e9es dans PostgreSQL, et la rapidit\u00e9 d'acc\u00e8s \u00e0 la base \u00e9tait essentielle pour nous, c'est pourquoi nous avons commenc\u00e9 \u00e0 shard PostgreSQL au niveau applicatif. Le sch\u00e9ma d\u00e9crit ci-dessus est relativement pratique pour cela : lors de l'ajout d'un nouveau shard, il suffit de mettre \u00e0 jour la configuration de PgBouncer et l'application peut directement travailler avec le nouveau shard.<\/p>\n<h3>R\u00e9silience de PgBouncer<\/h3>\n<p>Ce sch\u00e9ma a fonctionn\u00e9 jusqu'\u00e0 ce que l'unique instance de PgBouncer tombe en panne. Nous sommes dans AWS, o\u00f9 toutes les instances fonctionnent sur du mat\u00e9riel qui tombe p\u00e9riodiquement. Dans de tels cas, l'instance est simplement transf\u00e9r\u00e9e sur un nouveau mat\u00e9riel et fonctionne \u00e0 nouveau. C'est ce qui est arriv\u00e9 avec PgBouncer, cependant, il est devenu inaccessible. En cons\u00e9quence, notre service a \u00e9t\u00e9 indisponible pendant 25 minutes. AWS recommande d'utiliser la redondance c\u00f4t\u00e9 utilisateur dans de telles situations, ce qui n'avait pas \u00e9t\u00e9 mis en \u0153uvre chez nous \u00e0 ce moment-l\u00e0.<\/p>\n<p>Apr\u00e8s cela, nous avons r\u00e9fl\u00e9chi s\u00e9rieusement \u00e0 la tol\u00e9rance aux pannes de PgBouncer et des clusters PostgreSQL, car une telle situation pourrait se reproduire avec n'importe quelle instance de notre compte AWS.<\/p>\n<p>Nous avons construit le sch\u00e9ma de tol\u00e9rance aux pannes de PgBouncer de la mani\u00e8re suivante : tous les serveurs d'application se connectent \u00e0 un Network Load Balancer, derri\u00e8re lequel se trouvent deux PgBouncer. Chacun des PgBouncer surveille les m\u00eames master PostgreSQL de chaque shard. En cas de r\u00e9p\u00e9tition de la situation de panne d'une instance AWS, tout le trafic est redirig\u00e9 via un autre PgBouncer. La tol\u00e9rance aux pannes du Network Load Balancer est assur\u00e9e par AWS.<\/p>\n<p>Ce sch\u00e9ma permet d'ajouter facilement de nouveaux serveurs PgBouncer.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/2c1f1e7d9f7be4fdeb43858520d55e36.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<h2>Cr\u00e9ation d'un cluster PostgreSQL tol\u00e9rant aux pannes<\/h2>\n<p>Dans la r\u00e9solution de cette t\u00e2che, nous avons examin\u00e9 diff\u00e9rentes options : failover fait maison, repmgr, AWS RDS, Patroni.<\/p>\n<h3>Scripts faits maison<\/h3>\n<p>Peuvent surveiller le fonctionnement du master et, en cas de panne, promouvoir la r\u00e9plique au rang de master et mettre \u00e0 jour la configuration de PgBouncer.<\/p>\n<p>Les avantages de cette approche r\u00e9sident dans sa simplicit\u00e9 maximale, car vous \u00e9crivez vous-m\u00eame les scripts et comprenez exactement comment ils fonctionnent.<\/p>\n<p>Inconv\u00e9nients :<\/p>\n<ul>\n<li>Le master n'a pas pu tomber en panne, il pourrait plut\u00f4t s'agir d'une d\u00e9faillance r\u00e9seau. Le failover, sans le savoir, va promouvoir la r\u00e9plique au rang de master, tandis que l'ancien master continuera \u00e0 fonctionner. En cons\u00e9quence, nous aurons deux serveurs jouant le r\u00f4le de master et nous ne saurons pas lequel contient les derni\u00e8res donn\u00e9es actuelles. Cette situation est \u00e9galement appel\u00e9e split-brain.<\/li>\n<li>Nous nous sommes retrouv\u00e9s sans r\u00e9plique. Dans notre configuration, le master et une r\u00e9plique, apr\u00e8s le basculement, la r\u00e9plique est promue au rang de master et nous n'avons plus de r\u00e9pliques, donc nous devons ajouter manuellement une nouvelle r\u00e9plique.<\/li>\n<li>Un suivi suppl\u00e9mentaire du fonctionnement du failover est n\u00e9cessaire, sachant que nous avons 12 shards PostgreSQL, ce qui signifie que nous devons surveiller 12 clusters. Lors de l'augmentation du nombre de shards, il ne faut pas oublier de mettre \u00e0 jour le failover.<\/li>\n<\/ul>\n<p>Un failover fait maison semble tr\u00e8s complexe et n\u00e9cessite un support non trivial. Avec un seul cluster PostgreSQL, ce sera l'option la plus simple, mais elle n'est pas \u00e9volutive, donc elle ne nous convient pas.<\/p>\n<h3>Repmgr<\/h3>\n<p>Replication Manager pour les clusters PostgreSQL, qui g\u00e8re le fonctionnement du cluster PostgreSQL. Cependant, il n'y a pas de failover automatique 'pr\u00eat \u00e0 l'emploi', donc il sera n\u00e9cessaire d'\u00e9crire notre propre 'wrapper' autour de la solution existante. Cela pourrait donc \u00eatre encore plus compliqu\u00e9 que des scripts faits maison, c'est pourquoi nous n'avons m\u00eame pas essay\u00e9 Repmgr.<\/p>\n<h3>AWS RDS<\/h3>\n<p>Il prend en charge tout ce dont nous avons besoin, peut effectuer des sauvegardes et soutient un pool de connexions. Il a une bascule automatique : lorsque le ma\u00eetre meurt, la r\u00e9plique devient le nouveau ma\u00eetre, et AWS change l'enregistrement DNS vers le nouveau ma\u00eetre, tout en permettant aux r\u00e9pliques d'\u00eatre situ\u00e9es dans diff\u00e9rentes AZ.<\/p>\n<p>Parmi les inconv\u00e9nients, on peut noter l'absence de r\u00e9glages fins. Un exemple de r\u00e9glages fins : sur nos instances, il y a des limitations pour les connexions TCP, ce qui, malheureusement, ne peut pas \u00eatre fait dans 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>De plus, le prix de AWS RDS est presque deux fois plus \u00e9lev\u00e9 que le prix normal de l'instance, ce qui a \u00e9t\u00e9 la principale raison de notre refus de cette solution.<\/p>\n<h3>Patroni<\/h3>\n<p>C'est un mod\u00e8le en python pour g\u00e9rer PostgreSQL avec une bonne documentation, un failover automatique et un code source sur github.<\/p>\n<p>Les avantages de Patroni :<\/p>\n<ul>\n<li>Chaque param\u00e8tre de configuration est d\u00e9taill\u00e9, il est clair comment tout fonctionne ;<\/li>\n<li>Le failover automatique fonctionne 'pr\u00eat \u00e0 l'emploi' ;<\/li>\n<li>\u00c9crit en python, et comme nous \u00e9crivons beaucoup en python, il nous sera plus facile de r\u00e9soudre les probl\u00e8mes et \u00e9ventuellement de contribuer au d\u00e9veloppement du projet ;<\/li>\n<li>G\u00e8re compl\u00e8tement PostgreSQL, permet de changer la configuration sur tous les n\u0153uds du cluster, et si un red\u00e9marrage du cluster est n\u00e9cessaire pour appliquer une nouvelle configuration, cela peut \u00e9galement \u00eatre fait avec l'aide de Patroni.<\/li>\n<\/ul>\n<p>Inconv\u00e9nients :<\/p>\n<ul>\n<li>Il n'est pas clair \u00e0 partir de la documentation comment travailler correctement avec PgBouncer. M\u00eame si l'on peut difficilement appeler cela un inconv\u00e9nient, car la mission de Patroni est de g\u00e9rer PostgreSQL, et comment les connexions passeront par Patroni est notre probl\u00e8me.<\/li>\n<li>Il y a peu d'exemples d'impl\u00e9mentation de Patroni \u00e0 grande \u00e9chelle, alors qu'il y a de nombreux exemples d'impl\u00e9mentation \u00e0 partir de z\u00e9ro.<\/li>\n<\/ul>\n<p>En fin de compte, pour cr\u00e9er un cluster r\u00e9silient, nous avons choisi Patroni.<\/p>\n<h2>Le processus d'impl\u00e9mentation de Patroni<\/h2>\n<p>Avant Patroni, nous avions 12 shards PostgreSQL configur\u00e9s avec un ma\u00eetre et une r\u00e9plique en r\u00e9plication asynchrone. Les serveurs d'application acc\u00e9daient aux bases de donn\u00e9es via un \u00e9quilibreur de charge r\u00e9seau, derri\u00e8re lequel se trouvaient deux instances avec PgBouncer, et derri\u00e8re elles se trouvaient tous les serveurs PostgreSQL.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/8e5350d2466311593e11add30d5b1bdc.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<p>Pour d\u00e9ployer Patroni, nous devions choisir un stockage de configuration de cluster distribu\u00e9. Patroni fonctionne avec des syst\u00e8mes de stockage de configuration distribu\u00e9s, tels qu'etcd, Zookeeper et Consul. Nous avons justement un cluster Consul pleinement fonctionnel sur notre production, qui travaille en lien avec Vault et que nous n'utilisons pas autrement. Une excellente occasion de commencer \u00e0 utiliser Consul comme pr\u00e9vu.<\/p>\n<h3>Comment fonctionne Patroni avec Consul<\/h3>\n<p>Nous avons un cluster Consul compos\u00e9 de trois n\u0153uds et un cluster Patroni compos\u00e9 d'un leader et d'une r\u00e9plique (dans Patroni, le ma\u00eetre est appel\u00e9 leader du cluster, et les slaves sont appel\u00e9s r\u00e9pliques). Chaque instance du cluster Patroni envoie en permanence des informations sur l'\u00e9tat du cluster \u00e0 Consul. Par cons\u00e9quent, il est toujours possible de conna\u00eetre la configuration actuelle du cluster Patroni et qui est le leader en ce moment.<\/p>\n<p><img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/3234594b363904424fdce64c9d77fca5.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<p>Pour connecter Patroni \u00e0 Consul, il suffit de consulter la documentation officielle, qui indique qu'il est n\u00e9cessaire de sp\u00e9cifier l'h\u00f4te au format http ou https selon notre mode d'interaction avec Consul, ainsi que le sch\u00e9ma de connexion, de mani\u00e8re optionnelle :<\/p>\n<pre><code class=\"plaintext\">host : l'h\u00f4te:port pour le point de terminaison Consul, au format : http(s):\/\/host:port\nscheme : (optionnel) http ou https, par d\u00e9faut http<\/code><\/pre>\n<p>Cela semble simple, mais c'est l\u00e0 que les pi\u00e8ges commencent. Avec Consul, nous travaillons par connexion s\u00e9curis\u00e9e via https et notre configuration de connexion ressemblera \u00e0 ceci :<\/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>Mais cela ne fonctionne pas. Lors du d\u00e9marrage, Patroni ne peut pas se connecter \u00e0 Consul car il essaie toujours d'utiliser http.<\/p>\n<p>Comprendre le probl\u00e8me a \u00e9t\u00e9 facilit\u00e9 par le code source de Patroni. Heureusement, il est \u00e9crit en Python. Il s'av\u00e8re que le param\u00e8tre host n'est pas analys\u00e9, et le protocole doit \u00eatre sp\u00e9cifi\u00e9 dans le sch\u00e9ma. Voici \u00e0 quoi ressemble le bloc de configuration fonctionnel pour fonctionner avec Consul chez nous :<\/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>Nous avons donc choisi le stockage pour la configuration. Maintenant, il faut comprendre comment PgBouncer va changer sa configuration lors du changement de leader dans le cluster Patroni. La documentation ne r\u00e9pond pas \u00e0 cette question, car elle ne d\u00e9crit pas le fonctionnement avec PgBouncer.<\/p>\n<p>\u00c0 la recherche d'une solution, nous avons trouv\u00e9 un article (je ne me souviens malheureusement pas du titre) qui mentionnait que Consul-template avait beaucoup aid\u00e9 \u00e0 relier PgBouncer et Patroni. Cela nous a pouss\u00e9s \u00e0 explorer le fonctionnement de Consul-template.<\/p>\n<p>Il s'est av\u00e9r\u00e9 que Consul-template surveille en permanence la configuration du cluster PostgreSQL dans Consul. Lors du changement de leader, il met \u00e0 jour la configuration de PgBouncer et envoie la commande pour le red\u00e9marrer.<\/p>\n<p><img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/6cf92996a127bb6637ab81dc45fdd60a.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<p>Un grand avantage du template est qu'il est stock\u00e9 sous forme de code, donc lors de l'ajout d'une nouvelle shard, il suffit de faire un nouveau commit et de mettre \u00e0 jour le template automatiquement, en respectant le principe de l'Infrastructure as code.<\/p>\n<h3>Nouvelle architecture avec Patroni<\/h3>\n<p>En cons\u00e9quence, nous avons obtenu ce sch\u00e9ma de fonctionnement :<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/bf9a9eff675a26039e3f76b16c6cd713.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<p>Tous les serveurs d'application se connectent au r\u00e9partiteur de charge \u2192 derri\u00e8re se trouvent deux instances PgBouncer \u2192 sur chaque instance, Consul-template est en cours d'ex\u00e9cution et surveille l'\u00e9tat de chaque cluster Patroni, tout en veillant \u00e0 l'actualit\u00e9 de la config PgBouncer, qui dirige les requ\u00eates vers le leader actuel de chaque cluster.<\/p>\n<h3>Test manuel<\/h3>\n<p>Avant de passer en production, nous avons lanc\u00e9 ce sch\u00e9ma sur un petit environnement de test et v\u00e9rifi\u00e9 le fonctionnement du basculement automatique. Nous avons ouvert un tableau, d\u00e9plac\u00e9 un sticker et en m\u00eame temps 'tuions' le leader du cluster. Dans AWS, il suffit d'\u00e9teindre l'instance via 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 r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<p>Le sticker revenait en arri\u00e8re pendant 10 \u00e0 20 secondes, puis recommen\u00e7ait \u00e0 se d\u00e9placer normalement. Cela signifie que le cluster Patroni a fonctionn\u00e9 correctement : il a chang\u00e9 de leader, a envoy\u00e9 les informations \u00e0 Consul, et Consul-template a imm\u00e9diatement r\u00e9cup\u00e9r\u00e9 ces informations, remplac\u00e9 la configuration de PgBouncer et envoy\u00e9 la commande de rechargement.<\/p>\n<h2>Comment survivre \u00e0 une forte charge tout en conservant un temps d'arr\u00eat minimal ?<\/h2>\n<p>Tout fonctionne parfaitement ! Mais de nouvelles questions se posent : Comment cela fonctionnera-t-il sous charge \u00e9lev\u00e9e ? Comment d\u00e9ployer tout cela rapidement et en toute s\u00e9curit\u00e9 en production ?<\/p>\n<p>R\u00e9pondre \u00e0 la premi\u00e8re question nous aide \u00e0 utiliser un environnement de test, sur lequel nous effectuons des tests de charge. Il est compl\u00e8tement identique \u00e0 la production en termes d'architecture et dispose de donn\u00e9es de test g\u00e9n\u00e9r\u00e9es, dont le volume est \u00e0 peu pr\u00e8s \u00e9gal \u00e0 celui de la production. Nous d\u00e9cidons simplement de 'tuer' un des masters PostgreSQL pendant le test et de voir ce qui se passe. Mais avant cela, il est important de v\u00e9rifier le d\u00e9ploiement automatique, car sur cet environnement, nous avons plusieurs shards PostgreSQL, ce qui nous donnera un excellent test des scripts de configuration avant la mise en production.<\/p>\n<p>Les deux t\u00e2ches semblent ambitieuses, mais nous avons PostgreSQL 9.6. Peut-\u00eatre devrions-nous directement mettre \u00e0 jour vers 11.2 ?<\/p>\n<p>Nous avons d\u00e9cid\u00e9 de le faire en 2 \u00e9tapes : d'abord mettre \u00e0 jour la version vers 11.2, puis lancer Patroni.<\/p>\n<h3>Mise \u00e0 jour de PostgreSQL<\/h3>\n<p>Pour mettre \u00e0 jour rapidement la version de PostgreSQL, il est n\u00e9cessaire d'utiliser l'option <b>-k<\/b>, qui cr\u00e9e des liens physiques sur le disque et n'exige pas de copier vos donn\u00e9es. Pour des bases d'une taille de 300 \u00e0 400 Go, la mise \u00e0 jour ne prend qu'une seconde.<\/p>\n<p>Nous avons beaucoup de shards, donc la mise \u00e0 jour doit \u00eatre effectu\u00e9e de mani\u00e8re automatique. Pour cela, nous avons \u00e9crit un playbook Ansible qui ex\u00e9cute tout le processus de mise \u00e0 jour pour nous :<\/p>\n<pre><code class=\"plaintext\">\/usr\/lib\/postgresql\/11\/bin\/pg_upgrade \n&lt;b&gt;--lien &lt;\/b&gt;\n--ancien-datadir=&#039;&#039; --nouveau-datadir=&#039;&#039; \n --ancien-bindir=&#039;&#039;  --nouveau-bindir=&#039;&#039; \n --anciennes-options=&#039; -c fichier_config=&#039; \n --nouvelles-options=&#039; -c fichier_config=&#039;<\/code><\/pre>\n<p>Il est important de noter qu'avant de lancer la mise \u00e0 niveau, il est n\u00e9cessaire de l'ex\u00e9cuter avec le param\u00e8tre <b>\u2014v\u00e9rifier<\/b>, afin de s'assurer que la mise \u00e0 niveau est possible. De plus, notre script effectue un remplacement des configurations pendant la mise \u00e0 niveau. Notre script s'est ex\u00e9cut\u00e9 en 30 secondes, ce qui est un excellent r\u00e9sultat.<\/p>\n<h3>Lancement de Patroni<\/h3>\n<p>Pour r\u00e9soudre le deuxi\u00e8me probl\u00e8me, il suffit de jeter un \u0153il \u00e0 la configuration de Patroni. Dans le d\u00e9p\u00f4t officiel, il y a un exemple de configuration avec initdb, qui est responsable de l'initialisation d'une nouvelle base lors du premier lancement de Patroni. Mais comme nous avons d\u00e9j\u00e0 une base pr\u00eate, nous avons simplement supprim\u00e9 cette section de la configuration.<\/p>\n<p>Lorsque nous avons commenc\u00e9 \u00e0 installer Patroni sur un cluster PostgreSQL d\u00e9j\u00e0 existant et \u00e0 le d\u00e9marrer, nous avons rencontr\u00e9 un nouveau probl\u00e8me : les deux serveurs se lan\u00e7aient en tant que leader. Patroni ne sait rien de l'\u00e9tat pr\u00e9c\u00e9dent du cluster et essaie de lancer les deux serveurs comme deux clusters distincts avec le m\u00eame nom. Pour r\u00e9soudre ce probl\u00e8me, il est n\u00e9cessaire de supprimer le r\u00e9pertoire des donn\u00e9es sur le slave :<\/p>\n<pre><code class=\"plaintext\">rm -rf \/var\/lib\/postgresql\/<\/code><\/pre>\n<p><b>Cela doit \u00eatre fait uniquement sur le slave !<\/b><\/p>\n<p>Lorsque l'on connecte une r\u00e9plique propre, Patroni effectue un basebackup du leader et le restaure sur la r\u00e9plique, puis attrape l'\u00e9tat actuel \u00e0 l'aide des journaux WAL.<\/p>\n<p>Une autre difficult\u00e9 que nous avons rencontr\u00e9e est que tous les clusters PostgreSQL sont par d\u00e9faut appel\u00e9s main. Quand chaque cluster ne sait rien de l'autre, cela fonctionne. Mais lorsque vous souhaitez utiliser Patroni, tous les clusters doivent avoir un nom unique. La solution consiste \u00e0 changer le nom du cluster dans la configuration PostgreSQL.<\/p>\n<h3>Test de charge<\/h3>\n<p>Nous avons lanc\u00e9 un test qui simule le comportement des utilisateurs sur les tableaux. Lorsque la charge a atteint notre moyenne quotidienne, nous avons r\u00e9p\u00e9t\u00e9 exactement le m\u00eame test en \u00e9teignant une instance avec le leader PostgreSQL. Le failover automatique a fonctionn\u00e9 comme nous l'attendions : Patroni a chang\u00e9 de leader, Consul-template a mis \u00e0 jour la configuration de PgBouncer et a envoy\u00e9 une commande de reload. Sur nos graphiques dans Grafana, nous avons constat\u00e9 des retards de 20 \u00e0 30 secondes et un petit volume d'erreurs provenant des serveurs li\u00e9es \u00e0 la connexion \u00e0 la base de donn\u00e9es. C'est une situation normale, ces valeurs sont acceptables pour notre failover et clairement mieux qu'un temps d'arr\u00eat du service.<\/p>\n<h2>Sortie de Patroni en production<\/h2>\n<p>En fin de compte, nous avons \u00e9labor\u00e9 le plan suivant :<\/p>\n<ul>\n<li>D\u00e9ploiement de Consul-template sur les serveurs PgBouncer et d\u00e9marrage ;<\/li>\n<li>Mise \u00e0 jour de PostgreSQL vers la version 11.2 ;<\/li>\n<li>Changement de nom du cluster ;<\/li>\n<li>D\u00e9marrage du cluster Patroni.<\/li>\n<\/ul>\n<p>Notre sch\u00e9ma permet de r\u00e9aliser le premier point \u00e0 pratiquement tout moment, nous pouvons retirer chaque PgBouncer progressivement et proc\u00e9der au d\u00e9ploiement et au d\u00e9marrage de consul-template. C'est ce que nous avons fait.<\/p>\n<p>Pour un d\u00e9ploiement rapide, nous avons utilis\u00e9 Ansible, car tous les playbooks ont d\u00e9j\u00e0 \u00e9t\u00e9 test\u00e9s dans un environnement test, et le temps d'ex\u00e9cution du sc\u00e9nario complet \u00e9tait de 1,5 \u00e0 2 minutes pour chaque shard. Nous pouvions tout d\u00e9ployer progressivement sur chaque shard sans arr\u00eater notre service, mais nous aurions d\u00fb \u00e9teindre chaque PostgreSQL pendant quelques minutes. Dans ce cas, les utilisateurs dont les donn\u00e9es \u00e9taient sur ce shard n'auraient pas pu travailler pleinement durant ce temps, ce qui est inacceptable pour nous.<\/p>\n<p>La solution \u00e0 cette situation a \u00e9t\u00e9 une maintenance planifi\u00e9e, qui a lieu tous les 3 mois. C'est une fen\u00eatre pour les travaux planifi\u00e9s, lorsque nous arr\u00eatons compl\u00e8tement notre service et mettons \u00e0 jour les instances de bases de donn\u00e9es. Il restait une semaine avant la prochaine fen\u00eatre, et nous avons d\u00e9cid\u00e9 d'attendre et de nous pr\u00e9parer davantage. Pendant cette p\u00e9riode d'attente, nous avons \u00e9galement pris des pr\u00e9cautions : pour chaque shard PostgreSQL, nous avons lanc\u00e9 une r\u00e9plique de secours en cas d'\u00e9chec, afin de conserver les derni\u00e8res donn\u00e9es, et ajout\u00e9 une nouvelle instance pour chaque shard, qui devait devenir la nouvelle r\u00e9plique dans le cluster Patroni, afin de ne pas ex\u00e9cuter la commande pour supprimer des donn\u00e9es. Tout cela a contribu\u00e9 \u00e0 r\u00e9duire au maximum le risque d'erreur.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/29e5c5f50dbfebfe5665fa0aeb009728.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<p>Nous avons red\u00e9marr\u00e9 notre service, tout a fonctionn\u00e9 comme pr\u00e9vu, les utilisateurs ont continu\u00e9 \u00e0 travailler, mais sur les graphiques, nous avons observ\u00e9 une charge anormalement \u00e9lev\u00e9e sur les serveurs Consul.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/af0eef9ac235706c0aac62d2e1ee179d.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<p>Pourquoi ne l'avons-nous pas remarqu\u00e9 dans l'environnement de test ? Ce probl\u00e8me illustre tr\u00e8s bien qu'il est n\u00e9cessaire de suivre le principe de l'Infrastructure as Code et d'am\u00e9liorer toute l'infrastructure, depuis les environnements de test jusqu'\u00e0 la production. Sinon, il est tr\u00e8s facile d'obtenir un probl\u00e8me similaire \u00e0 celui que nous avons rencontr\u00e9. Que s'est-il pass\u00e9 ? Consul est d'abord apparu en production, puis dans les environnements de test, et au final, dans les environnements de test, la version de Consul \u00e9tait sup\u00e9rieure \u00e0 celle de la production. En effet, dans l'une des versions, une fuite du CPU lors de l'utilisation de consul-template a \u00e9t\u00e9 corrig\u00e9e. Par cons\u00e9quent, nous avons simplement mis \u00e0 jour Consul, r\u00e9solvant ainsi le probl\u00e8me.<\/p>\n<h3>Red\u00e9marrer le cluster Patroni<\/h3>\n<p>Cependant, nous avons rencontr\u00e9 un nouveau probl\u00e8me dont nous n'avions m\u00eame pas soup\u00e7onn\u00e9 l'existence. Lors de la mise \u00e0 jour de Consul, nous supprimons simplement le n\u0153ud Consul du cluster \u00e0 l'aide de la commande consul leave \u2192 Patroni se connecte \u00e0 un autre serveur Consul \u2192 tout fonctionne. Mais lorsque nous sommes arriv\u00e9s \u00e0 la derni\u00e8re instance du cluster Consul et avons envoy\u00e9 la commande consul leave, tous les clusters Patroni se sont simplement red\u00e9marr\u00e9s, et dans les journaux, nous avons vu l'erreur suivante :<\/p>\n<pre><code class=\"plaintext\">ERREUR : get_cluster\nTraceback (appel le plus r&eacute;cent en dernier) :\n...\nRetryFailedError : &#039;D&eacute;lai de nouvelle tentative d&eacute;pass&eacute;&#039;\nERREUR : Erreur de communication avec DCS\n&lt;b&gt;LOG : le syst&egrave;me de base de donn&eacute;es est arr&ecirc;t&eacute;&lt;\/b&gt;<\/code><\/pre>\n<p>Le cluster Patroni n'a pas pu obtenir d'informations sur son cluster et s'est red\u00e9marr\u00e9.<\/p>\n<p>Pour trouver une solution, nous avons contact\u00e9 les auteurs de Patroni via un probl\u00e8me sur github. Ils ont propos\u00e9 des am\u00e9liorations \u00e0 nos fichiers de configuration :<\/p>\n<pre><code class=\"python\">consul:\n consul.checks: []\nbootstrap:\n dcs:\n   retry_timeout: 8<\/code><\/pre>\n<p>Nous avons pu reproduire le probl\u00e8me dans un environnement de test et y avons test\u00e9 ces param\u00e8tres, mais malheureusement, ils n'ont pas fonctionn\u00e9.<\/p>\n<p>Le probl\u00e8me reste encore non r\u00e9solu. Nous pr\u00e9voyons d'essayer les options suivantes :<\/p>\n<ul>\n<li>Utiliser l'agent Consul sur chaque instance du cluster Patroni ;<\/li>\n<li>Corriger le probl\u00e8me dans le code.<\/li>\n<\/ul>\n<p>Nous comprenons d'o\u00f9 vient l'erreur : il semble que le probl\u00e8me provienne de l'utilisation du timeout par d\u00e9faut, qui n'est pas red\u00e9fini dans le fichier de configuration. Lorsque le dernier serveur Consul est supprim\u00e9 du cluster, l'ensemble du cluster Consul se fige pendant plus d'une seconde, ce qui emp\u00eache Patroni d'obtenir l'\u00e9tat du cluster et red\u00e9marre compl\u00e8tement le cluster.<\/p>\n<p>Heureusement, nous n'avons pas rencontr\u00e9 d'autres erreurs.<\/p>\n<h2>Bilan de l'utilisation de Patroni<\/h2>\n<p>Apr\u00e8s le d\u00e9marrage r\u00e9ussi de Patroni, nous avons ajout\u00e9 une r\u00e9plique suppl\u00e9mentaire dans chaque cluster. Maintenant, chaque cluster dispose d'un semblant de quorum : un leader et deux r\u00e9pliques, afin de se pr\u00e9munir contre le split-brain lors du basculement.<br \/>\n<img decoding=\"async\" style=\"display: block; margin: 0 auto;\" src=\"\/wp-content\/uploads\/2019\/06\/3bb4c0495fea274b04edd2e99b59eacb.png\" alt=\"Cluster PostgreSQL r\u00e9silient + Patroni. Exp\u00e9rience d&#039;impl\u00e9mentation\" \/><\/p>\n<p>Dans l'environnement de production, Patroni fonctionne depuis plus de trois mois. Pendant ce temps, il a d\u00e9j\u00e0 \u00e9t\u00e9 d'une grande aide. R\u00e9cemment, le leader d'un des clusters est tomb\u00e9 en panne sur AWS, le basculement automatique a fonctionn\u00e9 et les utilisateurs ont pu continuer \u00e0 travailler. Patroni a rempli sa t\u00e2che principale.<\/p>\n<p><b>Petit bilan de l'utilisation de Patroni :<\/b><\/p>\n<ul>\n<li>Facilit\u00e9 de modification de la configuration. Il suffit de modifier la configuration sur une instance et elle sera appliqu\u00e9e \u00e0 tout le cluster. Si un red\u00e9marrage est n\u00e9cessaire pour appliquer la nouvelle configuration, Patroni vous informera. Patroni peut red\u00e9marrer tout le cluster en une seule commande, ce qui est \u00e9galement tr\u00e8s pratique.<\/li>\n<li>Le basculement automatique fonctionne et a d\u00e9j\u00e0 r\u00e9ussi \u00e0 nous d\u00e9panner.<\/li>\n<li>Mise \u00e0 jour de PostgreSQL sans temps d'arr\u00eat de l'application. Il est n\u00e9cessaire de mettre d'abord \u00e0 jour les r\u00e9pliques vers la nouvelle version, puis de changer le leader dans le cluster Patroni et de mettre \u00e0 jour l'ancien leader. Un test du basculement automatique est \u00e9galement effectu\u00e9.<\/li>\n<\/ul>\n<p>Source : <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 - 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\/fr\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\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\/fr\/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 tol\u00e9rant aux pannes + Patroni. Exp\u00e9rience d'impl\u00e9mentation | ProHoster","description":"Dans cet article, je vais expliquer comment nous avons abord\u00e9 la question de la r\u00e9silience de PostgreSQL, pourquoi cela est devenu important pour nous et ce que nous avons finalement r\u00e9alis\u00e9.","canonical_url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/otkazoustojchivyj-klaster-postgresql-patroni-opyt-vnedreniya","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"fr_FR","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\/fr\/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\/fr\/wp-json\/wp\/v2\/posts\/35706","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/comments?post=35706"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/35706\/revisions"}],"predecessor-version":[{"id":172654,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/35706\/revisions\/172654"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media\/26749"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=35706"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=35706"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=35706"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}