ในการเริ่มต้นสร้าง PostgreSQL ด้วย patroni จะพบว่ามี config ค่อนข้างเยอะ จะมีวิธีไหนบ้างที่ง่ายๆ ที่จะ start database เพื่อทดลอง feature และ evaluate การทำงานใน case ต่างๆ เช่น กรณี fail over, read split-brain รวมถึงการ tuning เพื่อหา parameter ที่เหมาะสมไปใช้สำหรับงานจริง ในลักษณะของ sandbox ส่วนตัว แนะนำให้ใช้ template จาก Patroni: A Template for PostgreSQL HA with ZooKeeper, etcd or Consul โดยขั้นตอนตาม script ดังนี้
$ git clone https://github.com/zalando/patroni.git
$ cd patroni
$ docker build -t patroni .
$ docker-compose up -d
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4505a559a9e3 patroni "/bin/sh /entrypoint…" 43 seconds ago Up 42 seconds demo-etcd2
3b5183d6cee9 patroni "/bin/sh /entrypoint…" 43 seconds ago Up 42 seconds demo-etcd1
bd982fed4baa patroni "/bin/sh /entrypoint…" 43 seconds ago Up 42 seconds demo-patroni1
425d51032cb2 patroni "/bin/sh /entrypoint…" 43 seconds ago Up 42 seconds 0.0.0.0:5000-5001->5000-5001/tcp demo-haproxy
07cc2bfec72c patroni "/bin/sh /entrypoint…" 43 seconds ago Up 42 seconds demo-etcd3
cfa97b608d07 patroni "/bin/sh /entrypoint…" 43 seconds ago Up 42 seconds demo-patroni3
96a5b49cd787 patroni "/bin/sh /entrypoint…" 43 seconds ago Up 42 seconds demo-patroni2
จะเห็นว่า docker-compose.yml ได้ start patroni ขึ้นมา 3 node, etcd 3 node และ haproxy 1 node โดย expose port 5000 สำหรับ write และ 5001 สำหรับ read มาให้เลย
ทดสองเรียกใช้ cmd ของ patroni ใน cluster
$ docker exec -it demo-patroni1 patronictl list
+ Cluster: demo (7351235807499665431) --------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------+------------+---------+-----------+----+-----------+
| patroni1 | 172.19.0.6 | Leader | running | 1 | |
| patroni2 | 172.19.0.7 | Replica | streaming | 1 | 0 |
| patroni3 | 172.19.0.5 | Replica | streaming | 1 | 0 |
+----------+------------+---------+-----------+----+-----------+
ทดสอบ edit config ของ postgresql instance
$ docker exec -i demo-patroni1 patronictl edit-config --apply - --force <<'JSON'
{
synchronous_mode: "on",
synchronous_mode_strict: "on",
"postgresql":
{
"parameters":{
"synchronous_commit": "on",
"synchronous_standby_names": "*"
}
}
}
JSON
$ docker exec -it demo-patroni2 patronictl show-config
loop_wait: 10
maximum_lag_on_failover: 1048576
postgresql:
parameters:
max_connections: 100
synchronous_commit: 'on'
synchronous_standby_names: '*'
pg_hba:
- local all all trust
- host replication replicator all md5
- host all all all md5
use_pg_rewind: true
retry_timeout: 10
synchronous_mode: 'on'
synchronous_mode_strict: 'on'
ttl: 30
ทดสอบ switch over primary node
$ docker exec -it demo-patroni1 patronictl list
+ Cluster: demo (7351235807499665431) -+-----------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------+------------+--------------+-----------+----+-----------+
| patroni1 | 172.19.0.6 | Sync Standby | streaming | 3 | 0 |
| patroni2 | 172.19.0.7 | Leader | running | 3 | |
| patroni3 | 172.19.0.5 | Replica | streaming | 3 | 0 |
+----------+------------+--------------+-----------+----+-----------+
$ docker exec -it demo-patroni1 patronictl switchover --candidate patroni1 --force
Current cluster topology
+ Cluster: demo (7351235807499665431) -+-----------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------+------------+--------------+-----------+----+-----------+
| patroni1 | 172.19.0.6 | Sync Standby | streaming | 3 | 0 |
| patroni2 | 172.19.0.7 | Leader | running | 3 | |
| patroni3 | 172.19.0.5 | Replica | streaming | 3 | 0 |
+----------+------------+--------------+-----------+----+-----------+
2024-03-28 03:11:15.87873 Successfully switched over to "patroni1"
+ Cluster: demo (7351235807499665431) ------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------+------------+---------+---------+----+-----------+
| patroni1 | 172.19.0.6 | Leader | running | 3 | |
| patroni2 | 172.19.0.7 | Replica | stopped | | unknown |
| patroni3 | 172.19.0.5 | Replica | running | 3 | 0 |
+----------+------------+---------+---------+----+-----------+
ทดสอบใช้งาน postgresql
$ docker exec -i demo-patroni1 psql <<'SQL'
create table test(name varchar(50));
insert into test(name) values ('tao');
SQL
CREATE TABLE
INSERT 0 1
$ docker exec -i demo-patroni1 psql <<'SQL'
select * from test;
SQL
name
------
tao
(1 row)
ทดสอบ Postgresql HA ที่ setup ด้วย Patroni
Standby Server Tests
| No. | Test Scenario | Observation |
| 1 | Kill Postgresql process | Patroni จะ start process Postgresql เองโดยอัตโนมัติเมื่อเจอว่า postgresql process หายไป จากกระบวนการ health check – เนื่องจากเป็น process ที่ standby server จะไม่ส่งผลต่อ application ขณะทำการ write data |
| 2 | Stop Postgresql process | Patroni ทำการ start process เช่นเดียวกับ case 1 โดยไม่ส่งผลต่อ application ขณะทำการ write data |
| 3 | Reboot server | กรณีนี้จะต้อง set patroni service ให้เริ่มทำงานหลังจาก server boot เสร็จแล้ว ซึ่ง postgresql จะทำงานตามปกติหลังจาก service start – ไม่ส่งผลต่อ application ขณะทำการ write data |
| 4 | Stop patroni process | – Postgresql process ยังคงทำงานปกติ – ไม่สามารถใช้ cmd patronictl – ไม่ส่งผลต่อ application ขณะทำการ write data |
Primary Server Tests
| No | Test Scenario | Observation |
| 1 | Kill Postgresql process | Patroni ทำการ start postgresql process จากกระบวนการ health check แต่เนื่องจากเป็น node primary ที่มี primary lock อยู่แล้ว จึงไม่เกิดการกระบวนการ switch over ไปยัง replica node – ส่งผลต่อ application ไม่สามารถ write data ได้ในขณะ start process |
| 2 | Reboot server | ทำการ fail over ไปยัง standby server ด้วยกระบวนการเลือก standby server ที่อยู่ใน member หลังจากที่ server boot และ process postgresql ของ primary เดิมเริ่มทำงาน postgresql จะทำกระบวนการ pg_rewind เพื่อ update ข้อมูลล่าสุดและเปลี่ยนสถานะตัวเองเป็น standby server – ส่งผลต่อ application ไม่สามารถ write data ได้ |
| 3 | Stop/kill patroni process | – Standby Server จะ promote ตัวเองเป็น primary จากกระบวนการ acquired DCS Lock – Primary server เดิมยังคงทำงาน รวมถึงการเขียนก็ยังเขียนที่ Primary server เดิม ซึ่งทำให้เกิด 2 Primary server ทำงานในเวลาเดียวกัน – หลังจากที่ Patroni กลับมาทำงานอีกครั้งที่ Primary Server เดิม จะมีกระบวนการ pg_rewind เพื่อ update ข้อมูลล่าสุด และเปลี่ยนสถานะตัวเองเป็น Follower * ในระหว่างที่เกิดเหตุการณ์ 2 primary server ทำงานพร้อมกันอาจจะมี data loss ได้ จะต้อง set replication parameter ให้เหมาะสม |
Network Isolation Tests
| No. | Test Scenario | Observation |
| 1 | Primary server ไม่สามารถ connect กับ Standby server ได้ | – Postgresql หลุดจากการเป็น Primary server – เกิดกระบวนการเลือก Primary server ใหม่จาก member ที่เหลืออยู่ – ส่งผลให้ application ไม่สามารถเขียนข้อมูลได้ |
| 2 | Standby server ไม่สามารถ connect กับ Server ใน member ได้ | – Postgresql ยังคงทำงาน แต่จะไม่ถูกเลือกในกระบวนการเลือก Primary server ใหม่ – ไม่ส่งผลต่อการเขียนข้อมูลของ Applicaiton |
Reference
Patroni: A Template for PostgreSQL HA with ZooKeeper, etcd or Consul
