
{"id":7171,"date":"2025-02-19T12:44:50","date_gmt":"2025-02-19T12:44:50","guid":{"rendered":"https:\/\/test.opensource-db.in\/wp1\/?p=7171"},"modified":"2025-02-19T12:44:52","modified_gmt":"2025-02-19T12:44:52","slug":"step-by-step-guide-to-postgresql-ha-with-patroni-part-2","status":"publish","type":"post","link":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/","title":{"rendered":"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In our previous <a href=\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-i\/\">blog<\/a>, we explored the high availability (HA) architecture for PostgreSQL using <code>Patroni<\/code>, <code>etcd<\/code>, <code>HAproxy<\/code> and <code>PgBouncer<\/code>. We discussed how these components work together to ensure automatic failover, connection pooling, and efficient traffic distribution. Additionally, we covered the installation of each component to set up the HA environment.In this blog, we will focus on the configuration of Patroni with etcd, detailing how to properly set up and fine-tune these components for a resilient PostgreSQL cluster. We will also conduct a quick test to verify the setup and demonstrate the failover process to ensure seamless database availability.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prequesties<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Here are the IP addresses of the three servers that we used to configure Patroni with etcd.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li> server1 &#8211; 192.168.80.160<\/li>\n\n\n\n<li>server2 &#8211; 192.168.80.161<\/li>\n\n\n\n<li>server3 &#8211; 192.168.80.162<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Certain ports must be opened between the servers to ensure all components function seamlessly together. Here are the commands to add port (need to execute in all the five servers including two HAproxy servers).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#The port used for PostgreSQL client connections\nfirewall-cmd --zone=public --add-port=5432\/tcp --permanent\n\n#The port used for PgBouncer client connections\nfirewall-cmd --zone=public --add-port=6432\/tcp --permanent\n\n#The port used for http API of Patroni\nfirewall-cmd --zone=public --add-port=8008\/tcp --permanent\n\n#The port used for etcd client communication\nfirewall-cmd --zone=public --add-port=2379\/tcp --permanent\n\n#The port used for etcd peer communication\nfirewall-cmd --zone=public --add-port=2380\/tcp --permanent\n\n#The port used for http client connection to PostgreSQL backend\nfirewall-cmd --zone=public --add-port=5000\/tcp --permanent\n\n#The port used for https client connection to PostgreSQL backend\nfirewall-cmd --zone=public --add-port=5001\/tcp --permanent\n\n#Reload the firewalld services\nfirewall-cmd --reload<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Configuration of etcd<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After completing the installation of <code>etcd<\/code> on all the three nodes, verify it by checking the version.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>etcd --version\n\n#Output\netcd Version: 3.4.34\nGit SHA: c123b3ea3\nGo Version: go1.22.7\nGo OS\/Arch: linux\/amd64<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Server1<\/strong><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Edit your etcd configuration file in server1. As we are configuring the 3 nodes patroni cluster ,we are adding 3 IP&#8217;s in <code>ETCD_INITIAL_CLUSTER<\/code>. Add accordingly to your cluster.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server1 ~]# cd \/etc\/etcd\n&#91;root@server1 etcd]# ls -ltr\ntotal 8\n-rw-r--r-- 1 root root 1486 Jan 26 22:33 etcd.conf.orig\n-rw-r--r-- 1 root root  881 Feb  6 14:11 etcd.conf\n&#91;root@server1 etcd]# vi etcd.conf\n#specify the name of an etcd member\nETCD_NAME=server1\n\n# Configure the data directory\nETCD_DATA_DIR=\"\/var\/lib\/etcd\/server1\"\n\n# Configure the listen URLs\nETCD_LISTEN_PEER_URLS=\"http:\/\/192.168.80.160:2380,http:\/\/127.0.0.1:2380\"\nETCD_LISTEN_CLIENT_URLS=\"http:\/\/192.168.80.160:2379,http:\/\/127.0.0.1:2379\"\n\n# Configure the advertise URLs\nETCD_INITIAL_ADVERTISE_PEER_URLS=\"http:\/\/192.168.80.160:2380\"\nETCD_ADVERTISE_CLIENT_URLS=\"http:\/\/192.168.80.160:2379\"\n\n# Configure the initial cluster\nETCD_INITIAL_CLUSTER=\"server1=http:\/\/192.168.80.160:2380,server2=http:\/\/192.168.80.161:2380,server3=http:\/\/192.168.80.162:2380\"\n\n# Configure the initial cluster state\nETCD_INITIAL_CLUSTER_STATE=\"new\"\n\n# Configure the initial cluster token\nETCD_INITIAL_CLUSTER_TOKEN=\"etcd-cluster\"\n\n# Configure v2 API\nETCD_ENABLE_V2=\"true\"<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Server2<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Edit the etcd configuration file in server2.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server2 ~]# cd \/etc\/etcd\n&#91;root@server2 etcd]# ls -ltr\ntotal 8\n-rw-r--r-- 1 root root 1486 Jan 26 22:33 etcd.conf.orig\n-rw-r--r-- 1 root root  881 Feb  6 14:12 etcd.conf\n&#91;root@server2 etcd]# vi etcd.conf\n#specify the name of an etcd member\nETCD_NAME=server2\n\n# Configure the data directory\nETCD_DATA_DIR=\"\/var\/lib\/etcd\/server2\"\n\n# Configure the listen URLs\nETCD_LISTEN_PEER_URLS=\"http:\/\/192.168.80.161:2380,http:\/\/127.0.0.1:2380\"\nETCD_LISTEN_CLIENT_URLS=\"http:\/\/192.168.80.161:2379,http:\/\/127.0.0.1:2379\"\n\n# Configure the advertise URLs\nETCD_INITIAL_ADVERTISE_PEER_URLS=\"http:\/\/192.168.80.161:2380\"\nETCD_ADVERTISE_CLIENT_URLS=\"http:\/\/192.168.80.161:2379\"\n\n# Configure the initial cluster\nETCD_INITIAL_CLUSTER=\"server1=http:\/\/192.168.80.160:2380,server2=http:\/\/192.168.80.161:2380,server3=http:\/\/192.168.80.162:2380\"\n\n# Configure the initial cluster state\nETCD_INITIAL_CLUSTER_STATE=\"new\"\n\n# Configure the initial cluster token\nETCD_INITIAL_CLUSTER_TOKEN=\"etcd-cluster\"\n\n# Configure v2 API\nETCD_ENABLE_V2=\"true\"<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Server3<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Edit the etcd configuration file in server3.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server3 ~]# cd \/etc\/etcd\/\n&#91;root@server3 etcd]# ls -ltr\ntotal 8\n-rw-r--r-- 1 root root 1486 Jan 26 22:33 etcd.conf.orig\n-rw-r--r-- 1 root root  881 Feb  6 14:13 etcd.conf\n&#91;root@server3 etcd]# vi etcd.conf\n#specify the name of an etcd member\nETCD_NAME=server3\n\n# Configure the data directory\nETCD_DATA_DIR=\"\/var\/lib\/etcd\/server3\"\n\n# Configure the listen URLs\nETCD_LISTEN_PEER_URLS=\"http:\/\/192.168.80.162:2380,http:\/\/127.0.0.1:2380\"\nETCD_LISTEN_CLIENT_URLS=\"http:\/\/192.168.80.162:2379,http:\/\/127.0.0.1:2379\"\n\n# Configure the advertise URLs\nETCD_INITIAL_ADVERTISE_PEER_URLS=\"http:\/\/192.168.80.162:2380\"\nETCD_ADVERTISE_CLIENT_URLS=\"http:\/\/192.168.80.162:2379\"\n\n# Configure the initial cluster\nETCD_INITIAL_CLUSTER=\"server1=http:\/\/192.168.80.160:2380,server2=http:\/\/192.168.80.161:2380,server3=http:\/\/192.168.80.162:2380\"\n\n# Configure the initial cluster state\nETCD_INITIAL_CLUSTER_STATE=\"new\"\n\n# Configure the initial cluster token\nETCD_INITIAL_CLUSTER_TOKEN=\"etcd-cluster\"\n\n# Configure v2 API\nETCD_ENABLE_V2=\"true\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After configuring the etcd in all the three servers, enable and start the <code>etcd<\/code> service using <code>systemctl<\/code> <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl start etcd\nsystemctl enable etcd\nsystemctl status etcd<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We must now be able to see that the etcd services are up and running in all the three servers. Now, check the endpoint status using the below command after adding the servers and endpoints details to the <code>bash_profile<\/code> of three servers.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#Showing the server3 for your reference\n&#91;root@server3 ~]# vi .bash_profile\nserver1=192.168.80.160\nserver2=192.168.80.161\nserver3=192.168.80.162\nENDPOINTS=$server1:2379,$server2:2379,$server3:2379\n&#91;root@server3 ~]# . .bash_profile\n\n#After adding, check the status using the command \n&#91;root@server3 etcd]# etcdctl endpoint status --write-out=table --endpoints=$ENDPOINTS\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+\n|      ENDPOINT       |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+\n| 192.168.80.160:2379 | 16660bd8f0b37be2 |  3.5.18 |  234 kB |     false |      false |        16 |        788 |                788 |        |\n| 192.168.80.161:2379 | a1b073e6045e4de5 |  3.5.18 |  234 kB |      true |      false |        16 |        788 |                788 |        |\n| 192.168.80.162:2379 | e9aa0dcba4631717 |  3.5.18 |  234 kB |     false |      false |        16 |        788 |                788 |        |\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now, you can see that the <code>server2<\/code> is the leader of the cluster. Let&#8217;s breakdown what happens if the <code>server2<\/code> is down.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step1<\/strong> &#8211; Check the endpoint status of etcd cluster and stop the services in server2 as it is the leader of the cluster.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server2 ~]# etcdctl endpoint status --write-out=table --endpoints=$ENDPOINTS\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+\n|      ENDPOINT       |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+\n| 192.168.80.160:2379 | 16660bd8f0b37be2 |  3.5.18 |  234 kB |     false |      false |        16 |        788 |                788 |        |\n| 192.168.80.161:2379 | a1b073e6045e4de5 |  3.5.18 |  234 kB |      true |      false |        16 |        788 |                788 |        |\n| 192.168.80.162:2379 | e9aa0dcba4631717 |  3.5.18 |  234 kB |     false |      false |        16 |        788 |                788 |        |\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+\n&#91;root@server2 ~]# systemctl stop etcd<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step2<\/strong> &#8211; As the <code>etcd<\/code> is stopped in server2 , check the endpoint status now. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server2 ~]# etcdctl endpoint status --write-out=table --endpoints=$ENDPOINTS\n{\"level\":\"warn\",\"ts\":\"2025-02-19T14:42:58.041855+0530\",\"logger\":\"etcd-client\",\"caller\":\"v3@v3.5.18\/retry_interceptor.go:63\",\"msg\":\"retrying of unary invoker failed\",\"target\":\"etcd-endpoints:\/\/0xc0003fc000\/192.168.80.160:2379\",\"attempt\":0,\"error\":\"rpc error: code = DeadlineExceeded desc = latest balancer error: last connection error: connection error: desc = \\\"transport: Error while dialing: dial tcp 192.168.80.161:2379: connect: connection refused\\\"\"}\nFailed to get the status of endpoint 192.168.80.161:2379 (context deadline exceeded)\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+\n|      ENDPOINT       |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+\n| 192.168.80.160:2379 | 16660bd8f0b37be2 |  3.5.18 |  234 kB |     false |      false |        17 |        789 |                789 |        |\n| 192.168.80.162:2379 | e9aa0dcba4631717 |  3.5.18 |  234 kB |      true |      false |        17 |        789 |                789 |        |\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Note<\/strong> :As etcdctl is a utility used to interact with etcd , we can use it even when the etcd service is not running. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now , you were able to see server3 is the new leader of the cluster.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step3<\/strong> &#8211; Now, start the <code>etcd<\/code> services in <code>server2<\/code> and check whether the <code>server2<\/code> is joining the cluster or not.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server2 ~]# systemctl start etcd\n&#91;root@server2 ~]# etcdctl endpoint status --write-out=table --endpoints=$ENDPOINTS\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+\n|      ENDPOINT       |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+\n| 192.168.80.160:2379 | 16660bd8f0b37be2 |  3.5.18 |  234 kB |     false |      false |        17 |        790 |                790 |        |\n| 192.168.80.161:2379 | a1b073e6045e4de5 |  3.5.18 |  234 kB |     false |      false |        17 |        790 |                790 |        |\n| 192.168.80.162:2379 | e9aa0dcba4631717 |  3.5.18 |  234 kB |      true |      false |        17 |        790 |                790 |        |\n+---------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now, we were able to see that the <code>server2<\/code> is part of the cluster as a replica.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configuration of Patroni<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After completing the installation of <code>patroni<\/code> on all the three nodes, verify it by checking the version.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>patroni --version\n\n#Output\npatroni 4.0.4<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Server1<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Edit the <code>patroni<\/code> configuration file in server1. If you observe the configuration file, we configured the information of etcd, bootstrap , pg_hba , PostgreSQL  , parameters &amp; watchdog. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server1 ~]# cd \/etc\/patroni\/\n&#91;root@server1 patroni]# ls -ltr\ntotal 4\ndrwxr-xr-x 2 root root   26 Feb  6 14:46 callbacks\n-rw-r--r-- 1 root root 1194 Feb  6 15:10 patroni.yml\n&#91;root@server1 patroni]# vi patroni.yml\nscope: postgres\nnamespace: \/db\/\nname: server1\nrestapi:\n    listen: 192.168.80.160:8008\n    connect_address: 192.168.80.160:8008\netcd3:\n    hosts: 192.168.80.160:2379,192.168.80.161:2379,192.168.80.162:2379\nbootstrap:\n    dcs:\n        ttl: 30\n        loop_wait: 10\n        retry_timeout: 10\n        maximum_lag_on_failover: 1048576\n        postgresql:\n        use_pg_rewind: true\n    pg_hba:\n    - host replication replicator 192.168.80.160\/0 md5\n    - host replication replicator 192.168.80.161\/0 md5\n    - host replication replicator 192.168.80.162\/0 md5\n    - host replication all  0.0.0.0\/0 md5\n    - host all all 0.0.0.0\/0 md5\npostgresql:\n    listen: 192.168.80.160:5432\n    connect_address: 192.168.80.160:5432\n    data_dir: \/u01\/pgsql\/17\n    bin_dir: \/usr\/pgsql-17\/bin\n    authentication:\n        replication:\n            username: replicator\n            password: replicator\n        superuser:\n            username: postgres\n            password: postgres\n    parameters:\n        unix_socket_directories: '\/run\/postgresql\/'\nwatchdog:\n  mode: required\n  device: \/dev\/watchdog\n  safety_margin: 5\ntags:\n    nofailover: false\n    noloadbalance: false\n    clonefrom: false\n    nosync: false<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If we have to change any parameters of the <code>postgresql.conf<\/code> file like <code>shared_buffer<\/code> , <code>work_mem<\/code> mention them in the parameters sessions as per your compute and requirement. Watchdog devices are software or hardware mechanisms that will reset the whole system when they do not get a keepalive heartbeat within a specified timeframe. This adds an additional layer of fail safe in case usual Patroni split-brain protection mechanisms fail.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Server2<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Edit the configuration file in server2.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server2 ~]# vi \/etc\/patroni\/patroni.yml\nscope: postgres\nnamespace: \/db\/\nname: server2\nrestapi:\n    listen: 192.168.80.161:8008\n    connect_address: 192.168.80.161:8008\netcd3:\n    hosts: 192.168.80.160:2379,192.168.80.161:2379,192.168.80.162:2379\nbootstrap:\n    dcs:\n        ttl: 30\n        loop_wait: 10\n        retry_timeout: 10\n        maximum_lag_on_failover: 1048576\n        postgresql:\n        use_pg_rewind: true\n    pg_hba:\n    - host replication replicator 192.168.80.160\/0 md5\n    - host replication replicator 192.168.80.161\/0 md5\n    - host replication replicator 192.168.80.162\/0 md5\n    - host replication all  0.0.0.0\/0 md5\n    - host all all 0.0.0.0\/0 md5\npostgresql:\n    listen: 0.0.0.0:5432\n    connect_address: 192.168.80.161:5432\n    data_dir: \/u01\/pgsql\/17\n    bin_dir: \/usr\/pgsql-17\/bin\n    authentication:\n        replication:\n            username: replicator\n            password: replicator\n        superuser:\n            username: postgres\n            password: postgres\n    parameters:\n        unix_socket_directories: '\/run\/postgresql\/'\nwatchdog:\n  mode: required\n  device: \/dev\/watchdog\n  safety_margin: 5\ntags:\n    nofailover: false\n    noloadbalance: false\n    clonefrom: false\n    nosync: false<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Server3<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Edit the configuration file in server3.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server3 ~]# vi \/etc\/patroni\/patroni.yml\nscope: postgres\nnamespace: \/db\/\nname: server3\nrestapi:\n    listen: 192.168.80.162:8008\n    connect_address: 192.168.80.162:8008\netcd3:\n    hosts: 192.168.80.160:2379,192.168.80.161:2379,192.168.80.162:2379\nbootstrap:\n    dcs:\n        ttl: 30\n        loop_wait: 10\n        retry_timeout: 10\n        maximum_lag_on_failover: 1048576\n        postgresql:\n        use_pg_rewind: true\n    pg_hba:\n    - host replication replicator 192.168.80.160\/0 md5\n    - host replication replicator 192.168.80.161\/0 md5\n    - host replication replicator 192.168.80.162\/0 md5\n    - host replication all  0.0.0.0\/0 md5\n    - host all all 0.0.0.0\/0 md5\npostgresql:\n    listen: 192.168.80.162:5432\n    connect_address: 192.168.80.162:5432\n    data_dir: \/u01\/pgsql\/17\n    bin_dir: \/usr\/pgsql-17\/bin\n    authentication:\n        replication:\n            username: replicator\n            password: replicator\n        superuser:\n            username: postgres\n            password: postgres\n    parameters:\n        unix_socket_directories: '\/run\/postgresql\/'\nwatchdog:\n  mode: required\n  device: \/dev\/watchdog\n  safety_margin: 5\ntags:\n    nofailover: false\n    noloadbalance: false\n    clonefrom: false\n    nosync: false<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After configuring the patroni in all the three servers, start the <code>patroni<\/code> service using <code>systemctl<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl start patroni<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here, patroni will initialize the database as per the configurations given in <code>patroni.yml<\/code> file on the server chosen as the leader. We can see a message in log file as such.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>The database cluster will be initialized with locale \"en_US.UTF-8\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In the <code>replica<\/code> servers, patroni will simply take the basebackup of the <code>leader<\/code> . We can see a message in log file as such<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>INFO: replica has been created using basebackup<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">To check the list of servers in the patroni cluster , use the following command.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#Checing in server3\n&#91;root@server3 ~]# patronictl -c \/etc\/patroni\/patroni.yml list\n+ Cluster: postgres (7468243839154533834) ------+----+-----------+\n| Member  | Host           | Role    | State    | TL | Lag in MB |\n+---------+----------------+---------+----------+----+-----------+\n| server1 | 192.168.80.160 | Replica | running  |  4 |         0 |\n| server2 | 192.168.80.161 | Replica | running  |  3 |         0 |\n| server3 | 192.168.80.162 | Leader  | running  |  5 |           |\n+---------+----------------+---------+----------+----+-----------+<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here ,if we observe , <code>server3<\/code> is the current leader. We will test the failover after a quick test.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Quick test<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">In this quick test, let&#8217;s create a table in the current leader i.e., <code>server3<\/code> and check in one of the <code>replicas<\/code> .<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server3 ~]# su - postgres\n&#91;postgres@server3 ~]$ psql\npsql (17.2)\nType \"help\" for help.\n\npostgres=# create table emp (id int);\nCREATE TABLE\npostgres=# \\dt+\n                                   List of relations\n Schema | Name | Type  |  Owner   | Persistence | Access method |  Size   | Description \n--------+------+-------+----------+-------------+---------------+---------+-------------\n public | emp  | table | postgres | permanent   | heap          | 0 bytes | \n(1 row)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now, let&#8217;s whether the table is created or not on the <code>server1<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server1 ~]# su - postgres\n&#91;postgres@server1 ~]$ psql\npsql (17.2)\npostgres=# \\dt+\n                                   List of relations\n Schema | Name | Type  |  Owner   | Persistence | Access method |  Size   | Description \n--------+------+-------+----------+-------------+---------------+---------+-------------\n public | emp  | table | postgres | permanent   | heap          | 0 bytes | \n(1 row)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As, the table is created in the replica automatically, let&#8217;s see the failover part now.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Failover<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">As the current leader is <code>server3<\/code>, let&#8217;s check whether one of the replica is becoming as a primary or not once the <code>patroni<\/code> services is stopped on <code>server3<\/code> <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step1<\/strong> &#8211; Check the status of <code>patroni<\/code> and stop the Patroni service on server3.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server3 ~]# patronictl -c \/etc\/patroni\/patroni.yml list\n+ Cluster: postgres (7468243839154533834) ------+----+-----------+\n| Member  | Host           | Role    | State    | TL | Lag in MB |\n+---------+----------------+---------+----------+----+-----------+\n| server1 | 192.168.80.160 | Replica | running  |  4 |         0 |\n| server2 | 192.168.80.161 | Replica | running  |  3 |         0 |\n| server3 | 192.168.80.162 | Leader  | running  |  5 |           |\n+---------+----------------+---------+----------+----+-----------+\n#Stop the patroni\n&#91;root@server3 ~]# systemctl stop patroni\n&#91;root@server3 ~]# patronictl -c \/etc\/patroni\/patroni.yml list\n+ Cluster: postgres (7468243839154533834) ------+----+-----------+\n| Member  | Host           | Role    | State    | TL | Lag in MB |\n+---------+----------------+---------+----------+----+-----------+\n| server1 | 192.168.80.160 | Replica | running  |  4 |         0 |\n| server2 | 192.168.80.161 | Leader  | running  |  6 |           |\n| server3 | 192.168.80.162 | Replica | stopped  |    |   unknown |\n+---------+----------------+---------+----------+----+-----------+<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here, we can observe that the <code>server2<\/code> became the new leader and the <code>server3<\/code> became <code>replica<\/code> and it&#8217;s in the stopped state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Step2<\/strong> &#8211; Now, start the <code>patroni<\/code> services on <code>server3<\/code> and check the same status again.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;root@server3 ~]# systemctl start patroni\n#Check the list \n&#91;root@server3 ~]# patronictl -c \/etc\/patroni\/patroni.yml list\n+ Cluster: postgres (7468243839154533834) ------+----+-----------+\n| Member  | Host           | Role    | State    | TL | Lag in MB |\n+---------+----------------+---------+----------+----+-----------+\n| server1 | 192.168.80.160 | Replica | running  |  4 |         0 |\n| server2 | 192.168.80.161 | Leader  | running  |  6 |           |\n| server3 | 192.168.80.162 | Replica | running  |  5 |        16 |\n+---------+----------------+---------+----------+----+-----------+<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here we can observe that the <code>server3<\/code> is up and running again and following the <code>server2<\/code> . The advantage of using <code>patroni<\/code> is no manual intervention is required to re-join the failed leader back to the cluster unlike <code>repmgr<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In this blog, we covered the complete configuration of <code>Patroni<\/code> with <code>etcd<\/code> to set up a highly available PostgreSQL cluster. We started by configuring etcd on three servers, ensuring proper cluster formation and leader election. We then proceeded with Patroni installation and configuration, integrating it with etcd to manage automatic failover and replication. After setting up Patroni, we performed a quick test by creating a table on the leader node and verifying replication across replicas. Finally, we simulated a failover scenario, demonstrating how Patroni automatically promotes a replica to leader status when the primary node goes down. The process also highlighted how the failed leader seamlessly rejoins the cluster once it recovers. In the next blog of this series, we will integrate <code>HAProxy<\/code> and <code>PgBouncer<\/code> with our Patroni cluster.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Stay tuned for a deeper dive into these components and their configurations!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In our previous blog, we explored the high availability (HA) architecture for PostgreSQL using Patroni, etcd, HAproxy and PgBouncer. We [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":7177,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1,23,42,89],"tags":[],"class_list":["post-7171","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-others","category-postgresql-14","category-postgresql-15","category-postgresql-16"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v25.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2 - OpenSource DB<\/title>\n<meta name=\"robots\" content=\"noindex, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2 - OpenSource DB\" \/>\n<meta property=\"og:description\" content=\"In our previous blog, we explored the high availability (HA) architecture for PostgreSQL using Patroni, etcd, HAproxy and PgBouncer. We [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/\" \/>\n<meta property=\"og:site_name\" content=\"OpenSource DB\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/people\/OpenSource-DB\/100072970755470\/\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-19T12:44:50+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-19T12:44:52+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"945\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Venkat Akhil\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@opensource_db\" \/>\n<meta name=\"twitter:site\" content=\"@opensource_db\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Venkat Akhil\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/\"},\"author\":{\"name\":\"Venkat Akhil\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/person\/a37b142ecbf953189a4f9209b0b8d328\"},\"headline\":\"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2\",\"datePublished\":\"2025-02-19T12:44:50+00:00\",\"dateModified\":\"2025-02-19T12:44:52+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/\"},\"wordCount\":920,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#organization\"},\"image\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png\",\"articleSection\":[\"Others\",\"PostgreSQL 14\",\"PostgreSQL 15\",\"PostgreSQL 16\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/\",\"url\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/\",\"name\":\"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2 - OpenSource DB\",\"isPartOf\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png\",\"datePublished\":\"2025-02-19T12:44:50+00:00\",\"dateModified\":\"2025-02-19T12:44:52+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#primaryimage\",\"url\":\"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png\",\"contentUrl\":\"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png\",\"width\":1800,\"height\":945},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/test.opensource-db.in\/wp1\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#website\",\"url\":\"https:\/\/test.opensource-db.in\/wp1\/\",\"name\":\"OpenSource DB\",\"description\":\"Your Trusted OpenSource Databases partner\",\"publisher\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/test.opensource-db.in\/wp1\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#organization\",\"name\":\"OPENSOURCE DB PRIVATE LIMITED\",\"url\":\"https:\/\/test.opensource-db.in\/wp1\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2021\/10\/osdb-logo-tm-2.png\",\"contentUrl\":\"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2021\/10\/osdb-logo-tm-2.png\",\"width\":368,\"height\":120,\"caption\":\"OPENSOURCE DB PRIVATE LIMITED\"},\"image\":{\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/people\/OpenSource-DB\/100072970755470\/\",\"https:\/\/x.com\/opensource_db\",\"https:\/\/www.youtube.com\/channel\/UCmTI5h\",\"https:\/\/www.linkedin.com\/company\/opensource-db\",\"https:\/\/www.instagram.com\/opensource_db\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/person\/a37b142ecbf953189a4f9209b0b8d328\",\"name\":\"Venkat Akhil\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/522c0947d21b2c2c89f10698fd9131f9db4110f65c8d02b53d9b4559c7650865?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/522c0947d21b2c2c89f10698fd9131f9db4110f65c8d02b53d9b4559c7650865?s=96&d=mm&r=g\",\"caption\":\"Venkat Akhil\"},\"url\":\"https:\/\/test.opensource-db.in\/wp1\/author\/sudheer-sopensource-db-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2 - OpenSource DB","robots":{"index":"noindex","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"og_locale":"en_US","og_type":"article","og_title":"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2 - OpenSource DB","og_description":"In our previous blog, we explored the high availability (HA) architecture for PostgreSQL using Patroni, etcd, HAproxy and PgBouncer. We [&hellip;]","og_url":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/","og_site_name":"OpenSource DB","article_publisher":"https:\/\/www.facebook.com\/people\/OpenSource-DB\/100072970755470\/","article_published_time":"2025-02-19T12:44:50+00:00","article_modified_time":"2025-02-19T12:44:52+00:00","og_image":[{"width":1800,"height":945,"url":"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png","type":"image\/png"}],"author":"Venkat Akhil","twitter_card":"summary_large_image","twitter_creator":"@opensource_db","twitter_site":"@opensource_db","twitter_misc":{"Written by":"Venkat Akhil","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#article","isPartOf":{"@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/"},"author":{"name":"Venkat Akhil","@id":"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/person\/a37b142ecbf953189a4f9209b0b8d328"},"headline":"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2","datePublished":"2025-02-19T12:44:50+00:00","dateModified":"2025-02-19T12:44:52+00:00","mainEntityOfPage":{"@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/"},"wordCount":920,"commentCount":2,"publisher":{"@id":"https:\/\/test.opensource-db.in\/wp1\/#organization"},"image":{"@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#primaryimage"},"thumbnailUrl":"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png","articleSection":["Others","PostgreSQL 14","PostgreSQL 15","PostgreSQL 16"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/","url":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/","name":"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2 - OpenSource DB","isPartOf":{"@id":"https:\/\/test.opensource-db.in\/wp1\/#website"},"primaryImageOfPage":{"@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#primaryimage"},"image":{"@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#primaryimage"},"thumbnailUrl":"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png","datePublished":"2025-02-19T12:44:50+00:00","dateModified":"2025-02-19T12:44:52+00:00","breadcrumb":{"@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#primaryimage","url":"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png","contentUrl":"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png","width":1800,"height":945},{"@type":"BreadcrumbList","@id":"https:\/\/test.opensource-db.in\/wp1\/step-by-step-guide-to-postgresql-ha-with-patroni-part-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/test.opensource-db.in\/wp1\/"},{"@type":"ListItem","position":2,"name":"Step-by-Step Guide to PostgreSQL HA with Patroni: Part 2"}]},{"@type":"WebSite","@id":"https:\/\/test.opensource-db.in\/wp1\/#website","url":"https:\/\/test.opensource-db.in\/wp1\/","name":"OpenSource DB","description":"Your Trusted OpenSource Databases partner","publisher":{"@id":"https:\/\/test.opensource-db.in\/wp1\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/test.opensource-db.in\/wp1\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/test.opensource-db.in\/wp1\/#organization","name":"OPENSOURCE DB PRIVATE LIMITED","url":"https:\/\/test.opensource-db.in\/wp1\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/logo\/image\/","url":"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2021\/10\/osdb-logo-tm-2.png","contentUrl":"https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2021\/10\/osdb-logo-tm-2.png","width":368,"height":120,"caption":"OPENSOURCE DB PRIVATE LIMITED"},"image":{"@id":"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/people\/OpenSource-DB\/100072970755470\/","https:\/\/x.com\/opensource_db","https:\/\/www.youtube.com\/channel\/UCmTI5h","https:\/\/www.linkedin.com\/company\/opensource-db","https:\/\/www.instagram.com\/opensource_db\/"]},{"@type":"Person","@id":"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/person\/a37b142ecbf953189a4f9209b0b8d328","name":"Venkat Akhil","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/test.opensource-db.in\/wp1\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/522c0947d21b2c2c89f10698fd9131f9db4110f65c8d02b53d9b4559c7650865?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/522c0947d21b2c2c89f10698fd9131f9db4110f65c8d02b53d9b4559c7650865?s=96&d=mm&r=g","caption":"Venkat Akhil"},"url":"https:\/\/test.opensource-db.in\/wp1\/author\/sudheer-sopensource-db-com\/"}]}},"rttpg_featured_image_url":{"full":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png",1800,945,false],"landscape":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png",1800,945,false],"portraits":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png",1800,945,false],"thumbnail":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18-150x150.png",150,150,true],"medium":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18-300x158.png",300,158,true],"large":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18-1024x538.png",1024,538,true],"1536x1536":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18-1536x806.png",1536,806,true],"2048x2048":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png",1800,945,false],"ultp_layout_landscape_large":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png",1200,630,false],"ultp_layout_landscape":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png",870,457,false],"ultp_layout_portrait":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png",600,315,false],"ultp_layout_square":["https:\/\/test.opensource-db.in\/wp1\/wp-content\/uploads\/2025\/02\/image-18.png",600,315,false]},"rttpg_author":{"display_name":"Venkat Akhil","author_link":"https:\/\/test.opensource-db.in\/wp1\/author\/sudheer-sopensource-db-com\/"},"rttpg_comment":2,"rttpg_category":"<a href=\"https:\/\/test.opensource-db.in\/wp1\/category\/business\/others\/\" rel=\"category tag\">Others<\/a> <a href=\"https:\/\/test.opensource-db.in\/wp1\/category\/postgres\/postgresql-14\/\" rel=\"category tag\">PostgreSQL 14<\/a> <a href=\"https:\/\/test.opensource-db.in\/wp1\/category\/postgres\/postgresql-15\/\" rel=\"category tag\">PostgreSQL 15<\/a> <a href=\"https:\/\/test.opensource-db.in\/wp1\/category\/postgres\/postgresql-16\/\" rel=\"category tag\">PostgreSQL 16<\/a>","rttpg_excerpt":"In our previous blog, we explored the high availability (HA) architecture for PostgreSQL using Patroni, etcd, HAproxy and PgBouncer. We [&hellip;]","_links":{"self":[{"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/posts\/7171","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/comments?post=7171"}],"version-history":[{"count":3,"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/posts\/7171\/revisions"}],"predecessor-version":[{"id":7176,"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/posts\/7171\/revisions\/7176"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/media\/7177"}],"wp:attachment":[{"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/media?parent=7171"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/categories?post=7171"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/test.opensource-db.in\/wp1\/wp-json\/wp\/v2\/tags?post=7171"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}