HA #3: Cài đặt PgPool-II — Connection Clustering và Auto Failover
Thiết lập PgPool-II để routing query PostgreSQL, load balancing read query và tự động failover khi master bị down.
Hai bài trước đã có replication chạy và connection pool hoạt động. Nhưng application vẫn phải biết: “Đây là write query, gửi đến Master. Đây là read query, gửi đến Slave.” PgPool-II lấy trách nhiệm đó ra khỏi tay application — nó nhìn vào SQL, tự quyết định node nào xử lý, và tự động switch sang Slave khi Master đột ngột biến mất.
PgPool-II làm được gì?
| Tính năng | Mô tả |
|---|---|
| Connection pooling | Tương tự PgBouncer nhưng ít linh hoạt hơn |
| Query routing | SELECT → Slave, INSERT/UPDATE → Master |
| Load balancing | Phân phối SELECT đều giữa các Slave |
| Online recovery | Rebuild Slave bị lỗi tự động |
| Watchdog | Phát hiện node chết, promote Slave |
Khi nào dùng PgPool thay vì PgBouncer? Dùng PgPool khi bạn muốn transparent load balancing và auto-failover mà không thay đổi application. Dùng PgBouncer khi chỉ cần connection pooling đơn giản, hiệu năng cao, ít overhead. Nhiều setup production dùng cả hai: PgPool phía ngoài để route, PgBouncer phía trong để pool.
Môi trường
| Node | IP | Role |
|---|---|---|
| pgpool | 192.168.1.9 |
PgPool-II proxy |
| master | 192.168.1.10 |
PostgreSQL Master |
| slave1 | 192.168.1.11 |
PostgreSQL Slave 1 |
Cài đặt PgPool-II
1
2
sudo apt update
sudo apt install -y pgpool2
Kiểm tra version:
1
pgpool --version
Cấu hình
File cấu hình chính: /etc/pgpool2/pgpool.conf
Cấu hình kết nối backend
1
sudo nano /etc/pgpool2/pgpool.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# --- Backend nodes ---
backend_hostname0 = '192.168.1.10'
backend_port0 = 5432
backend_weight0 = 1
backend_data_directory0 = '/var/lib/postgresql/15/main'
backend_flag0 = 'ALLOW_TO_FAILOVER'
backend_hostname1 = '192.168.1.11'
backend_port1 = 5432
backend_weight1 = 1
backend_data_directory1 = '/var/lib/postgresql/15/main'
backend_flag1 = 'ALLOW_TO_FAILOVER'
# --- Listen ---
listen_addresses = '*'
port = 5432
# --- Connection pooling ---
num_init_children = 32
max_pool = 4
connection_cache = on
# --- Load balancing ---
load_balance_mode = on
ignore_leading_white_space = on
# --- Health check ---
health_check_period = 10
health_check_timeout = 20
health_check_user = 'pgpool_health'
health_check_password = 'health_pass'
health_check_database = 'postgres'
health_check_max_retries = 3
# --- Failover ---
failover_command = '/etc/pgpool2/failover.sh %d %h %p %D %m %H %M %P %r %R'
failover_on_backend_error = on
# --- Replication mode ---
replication_mode = off
master_slave_mode = on
master_slave_sub_mode = 'stream'
sr_check_period = 10
sr_check_user = 'replicator'
sr_check_password = 'strong_password_here'
Tạo user health check trên PostgreSQL
Trên Master, tạo user riêng cho PgPool health check:
1
2
CREATE ROLE pgpool_health WITH LOGIN PASSWORD 'health_pass';
GRANT CONNECT ON DATABASE postgres TO pgpool_health;
File pool_hba.conf
Cho phép connection từ application đến PgPool:
1
sudo nano /etc/pgpool2/pool_hba.conf
1
host all all 0.0.0.0/0 scram-sha-256
File pool_passwd
PgPool cần password file riêng. Tạo bằng công cụ pg_md5:
1
2
pg_md5 --md5auth --username=myappuser -p
# Nhập password khi được hỏi
File sẽ được ghi vào /etc/pgpool2/pool_passwd.
Script failover
Tạo script được gọi khi PgPool phát hiện Master chết:
1
sudo nano /etc/pgpool2/failover.sh
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
# $1: node id của node bị lỗi
# $7: hostname của node sẽ được promote (new master)
FAILED_NODE_HOST=$2
NEW_MASTER_HOST=$7
NEW_MASTER_PORT=$8
NEW_MASTER_DATA=$9
/usr/bin/ssh -T -i /var/lib/postgresql/.ssh/id_rsa \
postgres@${NEW_MASTER_HOST} \
"pg_ctl promote -D ${NEW_MASTER_DATA}"
1
sudo chmod +x /etc/pgpool2/failover.sh
Script này SSH vào Slave và chạy
pg_ctl promote. Cần setup SSH key từ pgpool server đến các PostgreSQL node trước.
Setup SSH key
Trên pgpool server:
1
sudo -u postgres ssh-keygen -t rsa -b 4096 -N "" -f /var/lib/postgresql/.ssh/id_rsa
Copy public key đến từng PostgreSQL node:
1
2
sudo -u postgres ssh-copy-id [email protected]
sudo -u postgres ssh-copy-id [email protected]
Khởi động PgPool
1
2
3
sudo systemctl enable pgpool2
sudo systemctl start pgpool2
sudo systemctl status pgpool2
Xác minh hoạt động
Xem trạng thái nodes
1
psql -h 127.0.0.1 -p 5432 -U myappuser -d myapp -c "SHOW pool_nodes;"
Output mong đợi:
1
2
3
4
node_id | hostname | port | status | lb_weight | role
---------+----------------+------+--------+-----------+--------
0 | 192.168.1.10 | 5432 | up | 0.500000 | primary
1 | 192.168.1.11 | 5432 | up | 0.500000 | standby
Test load balancing
Chạy nhiều SELECT và xem PgPool phân phối:
1
2
3
4
for i in {1..10}; do
psql -h 127.0.0.1 -p 5432 -U myappuser -d myapp \
-c "SELECT inet_server_addr();" -t
done
Kết quả nên xen kẽ giữa 192.168.1.10 và 192.168.1.11.
Test failover
Dừng PostgreSQL trên Master:
1
2
# Trên 192.168.1.10
sudo systemctl stop postgresql
Sau vài giây (bằng health_check_period), PgPool sẽ phát hiện và gọi failover.sh. Kiểm tra lại:
1
psql -h 127.0.0.1 -p 5432 -U myappuser -d myapp -c "SHOW pool_nodes;"
Slave sẽ được promote, hiện role = primary. Application tiếp tục chạy mà không cần thay đổi connection string.
Những thứ hay gặp
health_check_user không có quyền CONNECT — PgPool báo node down dù PostgreSQL đang chạy. Kiểm tra pg_hba.conf và grant quyền connect.
Failover script không chạy được do SSH — Kiểm tra SSH key, permission của .ssh/ và authorized_keys. File authorized_keys phải chmod 600, thư mục .ssh/ phải chmod 700.
Query bị route sai node — PgPool parse SQL để quyết định routing. Một số query phức tạp có thể bị nhầm. Dùng /*NO LOAD BALANCE*/ hint để ép query về Master:
1
/*NO LOAD BALANCE*/ SELECT * FROM sensitive_table;
Split-brain sau failover — Nếu Master cũ phục hồi, đừng để nó tự join lại cluster. Cần rebuild nó thành Slave mới (chạy pg_basebackup từ Master hiện tại).
Tóm tắt série HA PostgreSQL
| Bài | Công cụ | Giải quyết |
|---|---|---|
| #1 | Master-Slave Replication | Phân tải read, có bản dự phòng |
| #2 | PgBouncer | Tái sử dụng connection, giảm overhead |
| #3 | PgPool-II | Auto routing, load balancing, failover |
Ba lớp này cộng lại tạo thành một PostgreSQL cluster có khả năng chịu tải cao, tự phục hồi khi node chính gặp sự cố, và trong suốt với application.
Có câu hỏi hoặc gặp lỗi khác — Facebook: V-CODER LOG