PostgreSQL 完全指南 / 16 - 高可用架构
第 16 章 · 高可用架构
高可用(High Availability)确保数据库服务的持续可用性。本章介绍 Patroni、pgpool-II、PgBouncer 和读写分离。
16.1 高可用方案对比
| 方案 | 故障切换 | 自动切换 | 复杂度 | 适用规模 |
|---|---|---|---|---|
| Patroni | 秒级 | ✅ | 中 | 任意 |
| pgpool-II | 秒级 | ✅ | 高 | 中型 |
| repmgr | 分钟级 | ✅ | 低 | 中小型 |
| Stolon | 秒级 | ✅ | 高 | K8s |
| CloudNativePG | 秒级 | ✅ | 中 | K8s |
16.2 Patroni
Patroni 是最流行的 PostgreSQL HA 解决方案。
架构
┌─────────┐ ┌─────────┐ ┌─────────┐
│ PG 主 │ │ PG 从1 │ │ PG 从2 │
│ Patroni │ │ Patroni │ │ Patroni │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
└───────────────┼───────────────┘
│
┌──────┴──────┐
│ DCS (etcd/ │
│ Consul/ │
│ ZooKeeper) │
└─────────────┘
Docker Compose 部署
version: "3.8"
services:
etcd:
image: bitnami/etcd:3.5
environment:
ALLOW_NONE_AUTHENTICATION: "yes"
ETCD_ADVERTISE_CLIENT_URLS: "http://etcd:2379"
ports:
- "2379:2379"
pg-master:
image: postgres:17
environment:
POSTGRES_PASSWORD: password
volumes:
- pg_master:/var/lib/postgresql/data
pg-replica:
image: postgres:17
environment:
POSTGRES_PASSWORD: password
volumes:
- pg_replica:/var/lib/postgresql/data
volumes:
pg_master:
pg_replica:
Patroni 配置示例
# patroni.yml
scope: pg-cluster
name: pg-node-1
restapi:
listen: 0.0.0.0:8008
connect_address: 10.0.0.1:8008
etcd3:
hosts: etcd1:2379,etcd2:2379,etcd3:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
wal_level: replica
hot_standby: on
max_wal_senders: 5
max_replication_slots: 5
wal_log_hints: on
postgresql:
listen: 0.0.0.0:5432
connect_address: 10.0.0.1:5432
data_dir: /var/lib/postgresql/data
authentication:
superuser:
username: postgres
password: password
replication:
username: replicator
password: rep_password
16.3 PgBouncer(连接池)
PgBouncer 是最流行的 PostgreSQL 连接池。
安装与配置
# 安装
sudo apt install pgbouncer
# Docker
docker run -d --name pgbouncer \
-p 6432:5432 \
-e DATABASE_URL="postgres://user:pass@pg-host:5432/mydb" \
edoburu/pgbouncer
# pgbouncer.ini
[databases]
mydb = host=127.0.0.1 port=5432 dbname=mydb
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 50
min_pool_size = 10
reserve_pool_size = 5
reserve_pool_timeout = 3
server_lifetime = 3600
server_idle_timeout = 600
log_connections = 1
log_disconnections = 1
连接池模式
| 模式 | 说明 | 适用场景 |
|---|---|---|
session | 连接绑定会话 | 需要会话级对象(临时表、PREPARE) |
transaction | 连接在事务级别复用 | 推荐大多数场景 |
statement | 每条语句后释放连接 | 最高复用率,不支持多语句事务 |
⚠️ 注意事项:transaction 模式下不能使用 LISTEN/NOTIFY、临时表、PREPARE 语句等会话级功能。
16.4 pgpool-II
pgpool-II 提供连接池、负载均衡、故障切换、查询缓存等功能。
docker run -d --name pgpool \
-p 9999:9999 \
-e PGPOOL_BACKEND_NODES="0:pg-master:5432,1:pg-replica:5432" \
-e PGPOOL_SR_CHECK_USER=replicator \
-e PGPOOL_SR_CHECK_PASSWORD=password \
-e PGPOOL_ENABLE_LOAD_BALANCING=on \
bitnami/pgpool:4
16.5 读写分离
-- 应用层读写分离(推荐)
-- 写操作 → 主库(端口 5432)
-- 读操作 → 从库(端口 5433)
-- PgBouncer 配置多个数据库
-- pgbouncer.ini
[databases]
mydb_rw = host=primary port=5432 dbname=mydb
mydb_ro = host=replica port=5432 dbname=mydb
# Python 示例
import psycopg2
# 写连接(主库)
write_conn = psycopg2.connect("host=primary port=6432 dbname=mydb_rw")
# 读连接(从库)
read_conn = psycopg2.connect("host=replica port=6432 dbname=mydb_ro")
业务场景
| 场景 | 推荐方案 |
|---|---|
| 中小规模 HA | Patroni + etcd |
| K8s 环境 | CloudNativePG Operator |
| 连接池 | PgBouncer(transaction 模式) |
| 读写分离 | PgBouncer + 多数据库路由 |
| 多活/跨地域 | Patroni + 同步复制 |