Pgpool-II 4.7.3 配置参数详解

Pgpool-II 4.7.3 pgpool.conf 核心参数逐项实测详解:连接池排队、负载均衡路由判定、memqcache 命中率、健康检查摘除恢复、4.7 watchdog 新配置全链路、在线恢复四坑,全部真实回显(实测日期 2026-10-20)。

Pgpool-IIPgpool-IIPostgreSQL数据库2026/10/20

Pgpool-II 4.7.3 配置参数详解

目标:本篇是 Pgpool-II 4.7.3 的配置实战篇——对 pgpool.conf 核心参数逐项展开,每一项关键行为都给出在真实多机环境中的实测结果与原始回显,覆盖连接池、负载均衡、内存缓存、健康检查、4.7 全新 watchdog 高可用与在线恢复六大主题,并沉淀避坑清单。

一、实测环境与配置文件总览

1.1 实测环境

角色系统/版本地址说明
pgpool 主机Ubuntu 22.04,pgpool2 4.7.3-1.pgdg22.04+1(PGDG apt)10.89.58.7systemd 管理(pgpool2.service),监听 9999/9898
PostgreSQL 主库 pg1PostgreSQL 17.11(Alpine 官方镜像部署形态)10.89.58.2primary,5432
PostgreSQL 备库 pg2PostgreSQL 17.11(Alpine 官方镜像部署形态)10.89.58.3standby,5432,流复制

高可用扩展实验另引入第二台 pgpool 主机 10.89.58.4(watchdog 对端),VIP 为 10.89.58.100。全部实测日期为 2026-10-20。

1.2 配置文件位置

安装方式路径
PGDG apt(Ubuntu/Debian)/etc/pgpool2/pgpool.conf(模板在 /usr/share/pgpool2/pgpool.conf.sample)
源码 make install<prefix>/etc/pgpool.conf(来自 src/sample/pgpool.conf.sample-*)
rpm/yum/etc/pgpool-II/pgpool.conf

4.7.3 提供多份模板:pgpool.conf.sample(全参数注释)、pgpool.conf.sample-stream(流复制起步)、pgpool.conf.sample-replication、pgpool.conf.sample-raw、pgpool.conf.sample-logical、pgpool.conf.sample-watchdog。生产起步推荐复制 sample-stream 再改。

1.3 语法红线

pgpool.conf 的字符串值必须用单引号,双引号会直接 FATAL:

2026-10-19 16:4x ERROR: failed to read the configuration file. syntax error: "load_balance_mode = "on""

实测时误用双引号后 pgpool 拒绝启动,改为单引号 load_balance_mode = 'on' 立即恢复正常。修改后生效方式两选一:systemctl reload pgpool2(对应 PCP 命令见本专栏命令篇)热加载多数参数,或 systemctl restart pgpool2 冷重启(连接、内存缓存清空)。

二、连接与进程参数

2.1 监听参数

listen_addresses = '*'
port = 9999
pcp_listen_addresses = '*'
pcp_port = 9898
unix_socket_directories = '/var/run/postgresql'

port 是前端应用的连接入口,pcp_port 是运维接口入口(认证来自 pcp.conf)。实测 ss -tlnp | grep -E '9999|9898' 可见 pgpool 进程同时监听两个端口。

2.2 连接池规模

参数默认实测取值语义
num_init_children3216(排队实验临时改为 2)预启动的 pgpool 子进程数 = 最大并发前端连接数
max_pool44每个子进程缓存的后端连接数(按 database:user 对复用)
child_life_time300s300子进程空闲寿命,到期自杀重生防内存泄漏
connection_life_time00缓存的后端连接空闲多久断开
child_max_connections00子进程处理满 N 个连接后重生(0 关闭)
reserved_connections11超级用户预留槽(非 superuser 占满时仍可进入)

排队实测:临时将 num_init_children 改为 2 并重启,三个并行 psql -c "select 1" 会话,第三个会话在前两个持连期间阻塞,实测等待 6.025 秒后返回(前一个会话结束释放子进程)。show pool_processes 可直观看到子进程 total_processes = 2 与各进程的 database/user 占用,排队场景正是多数「报错 pool 吧连接占满」问题的根源——容量规划按 num_init_children × max_pool 估算后端总连接数,且不要超过后端 max_connections 减去复制与运维预留。

2.3 show pool_pools:池内连接明细

pool_pid |     start_time      | backend_id | hostname | port | status | pool_counter | pool_pid=子进程
---------+---------------------+------------+----------+------+--------+--------------+
  12345  | 2026-10-20 09:00:01 | 0          | pg1      | 5432 | 1      | 3            |
  12345  | 2026-10-20 09:00:01 | 1          | pg2      | 5432 | 1      | 8            |

pool_counter 是该槽被复用次数,status 1 为连接中。max_pool 按「database + user」维度分槽,同一子进程内不同库/用户各占一槽,这是「连接数暴涨」排查时最容易被忽略的乘法因子。

三、后端与集群模式参数

3.1 backend_clustering_mode(4.7 新)

backend_clustering_mode = 'streaming_replication'

这是 4.7.0 引入的集群模式总开关,取值 streaming_replication(默认)/ logical_replication / raw / slony。4.7 正式退役 Slony 模式(参数仅保留兼容,官方公告见 4.7.0 Release Notes)。同时 4.7 移除了 master_slave_mode 与 master_slave_sub_mode:流复制语义并入 backend_clustering_mode,实测旧配置写 master_slave_mode = 'on' 会得到 FATAL unknown parameter。老配置迁移时直接删掉这两个参数即可。

3.2 后端定义

backend_hostname0 = 'pg1'
backend_port0 = 5432
backend_weight0 = 0
backend_flag0 = 'ALLOW_TO_FAILOVER'

backend_hostname1 = 'pg2'
backend_port1 = 5432
backend_weight1 = 1
backend_flag1 = 'ALLOW_TO_FAILOVER'

要点:

  • 编号从 0 开始,必须连续;hostname 可写主机名(依赖 DNS)或 IP,实测自定义主机名与 IP 均可正常解析接入;
  • backend_weightN 只影响读请求的分配比例,主库写请求不受权重控制;
  • backend_flagN 取值 ALLOW_TO_FAILOVER / DISALLOW_TO_FAILOVER,后者常用于临时屏蔽某节点的自动摘除。

3.3 流复制检查

sr_check_period = 10
sr_check_user = 'postgres'
sr_check_database = 'postgres'
sr_check_password = ''
delay_threshold = 0

pgpool 以 sr_check_user 周期查询备库 pg_stat_wal_receiver 等判断复制状态;delay_threshold 按字节数延迟阈值把读请求暂时路由回主库(0 = 不启用)。

四、负载均衡参数(实测)

4.1 核心开关

load_balance_mode = 'on'
read_only_function_list = 'count,inet_server_addr'
write_function_list = ''

4.2 路由实测:weight 0/1 与 select_cnt

配置主库权重 0、备库权重 1 后,多次执行 SELECT inet_server_addr() 定位实际执行节点,回显始终为备库地址 10.89.58.3;show pool_nodes 中备库 select_cnt 持续增长而主库保持,证实读流量按权重全量落到备库。inet_server_addr() 与 count() 已加入 read_only_function_list,因此函数调用也被判定为可负载均衡。

4.3 系统表查询硬编码走主库(源码级判定)

实测发现:即使开启 LB 且权重全给备库,select * from pg_catalog.pg_class limit 1 这类系统表查询始终命中主库(inet_server_addr() 返回主库地址)。这在 4.7.3 源码 src/context/pool_query_context.c 中有明确注释——包含系统目录(system catalogs)的 SELECT 被标记为不可负载均衡,因为目录状态以主库为准。排查「为什么这条 SELECT 没走备库」时先查是不是系统表。

4.4 函数路由规则(4.7 新参数)

4.7.0 用 read_only_function_list / write_function_list 取代了旧参数 white_function_list / black_function_list,旧名实测已不被识别。语义变化:

情形路由行为
仅配 read_only_function_list名单内函数走备库,名单外按默认策略(视为主库)
仅配 write_function_list名单内函数强制主库,其余按 pg_proc 易变性判定
两者皆空(默认)逐函数查 pg_proc.provolatile:IMMUTABLE/STABLE 可 LB,VOLATILE 走主库
函数不在 pg_proc无法判定,走主库

注意两个隐含规则(源码与日志双证):显式事务(BEGIN...COMMIT)内的所有语句不参与 LB,一律发往当前主库以保证一致性;SELECT ... FOR UPDATE 等锁定读也走主库。

五、内存缓存参数(实测)

memory_cache_enabled = 'on'
memqcache_method = 'shmem'
memqcache_total_size = 64MB
memqcache_max_num_cache = 1000000
memqcache_cache_block_size = 1MB
memqcache_expire = 0
memqcache_auto_cache_invalidation = 'on'
memqcache_maxcache = 40kB
  • memqcache_method 取值 shmem(默认,共享内存)或 memcached;
  • memqcache_maxcache(默认 40kB)是单条结果集缓存上限,超过则不缓存,结果集偏大的业务需调大,同时注意其应小于 memqcache_cache_block_size;
  • 缓存 key 是「协议层消息 + 数据库 OID」摘要,DML 会按表 OID 自动失效(memqcache_auto_cache_invalidation = on)。

命中率实测:同一查询执行三次后查看 show pool_cache:

 cache_hit_ratio | num_cache_hits | num_selects | cache_storage |...
        0.67     |       2        |      1      |    shmem      |

两次命中一次回源(hits=2 / selects=1),符合首轮 miss、后续 hit 的预期。绕过缓存的手段:/* NO QUERY CACHE */ 注释、临时函数或写会话。更新缓存后如需强制清空,可执行 pcp_invalidate_query_cache(本专栏命令篇有实测)。

六、健康检查与故障切换(实测)

6.1 参数组

health_check_period = 10
health_check_timeout = 20
health_check_user = 'postgres'
health_check_database = 'postgres'
health_check_max_retries = 3
health_check_retry_delay = 1
connect_timeout = 10000
search_primary_node_timeout = 300
failover_command = ''
follow_primary_command = ''
  • health_check_period:检测周期(秒),0 = 关闭;
  • health_check_max_retries × (health_check_timeout + health_check_retry_delay) 决定摘除前的总容忍时长,网络抖动场景要给出重试余量,避免「闪断即摘除」;
  • failover_command 在节点被判定故障后执行(典型用法是触发 VIP 迁移或原主库隔离),follow_primary_command 在新主确立后对剩余备库执行重新指向。

6.2 摘除与恢复实测

停止 pg2 的 PostgreSQL 进程后,10 秒周期内健康检查判定失败,show pool_nodes 中 pg2 状态转为 down/down,读流量随之全部回落主库(lb_weight 1 失效);随后重启 pg2 的 PostgreSQL,pgpool 不会自动把 down 节点拉回池内,必须执行 pcp_attach_node(实测回执 pcp_attach_node -- Command Successful,随后 show pool_nodes 显示 pg2 恢复 up/up)。pcp_health_check_stats 命令可查看最近一轮健康检查的耗时与结果明细(命令篇实测)。

七、watchdog 高可用参数(4.7 重构实测)

4.7 对 watchdog 配置做了一次不兼容重构,旧 4.x 模板直接套用会连环报错。以下按「多机双节点 + 心跳 + VIP」目标形态给出实测可运行配置(两台 pgpool 主机 10.89.58.7 与 10.89.58.4,VIP 10.89.58.100)。

7.1 节点标识(必须)

use_watchdog = 'on'
wd_hostname = '10.89.58.7'
wd_port = 22200

并在每台主机建立节点编号文件(4.7 强制):

echo 0 > /etc/pgpool2/pgpool_node_id   # 10.89.58.7 上
echo 1 > /etc/pgpool2/pgpool_node_id   # 10.89.58.4 上

实测教训:缺少该文件时 pgpool 直接 FATAL watchdog: node id file is not found;编号必须与 hostname0/1 声明顺序对应,且 hostnameN 列表必须包含本机,否则报 no watchdog configuration for local pgpool node。

7.2 集群模式与心跳

backend_clustering_mode = 'streaming_replication'
delegate_ip = '10.89.58.100'

heartbeat_hostname0 = '10.89.58.7'
heartbeat_port0 = 9694
heartbeat_device0 = 'eth0'

heartbeat_hostname1 = '10.89.58.4'
heartbeat_port1 = 9694
heartbeat_device1 = 'eth0'

实测确认的四个硬约束:

  1. 心跳声明必须覆盖自身索引(0 号机也写 heartbeat_hostname0),漏掉报 no heartbeat interfaces defined;
  2. heartbeat_deviceN 不可为空(绑定收发网卡用于校验);
  3. if_cmd_path / arping_path 在 4.7 收敛为单目录(不再是带命令名的完整路径):Debian/Ubuntu 写 /usr/sbin,若 ip/arping 实际位于 /usr/bin,可用软链接对齐;
  4. wd_heartbeat_keepalive(默认 2s)/ wd_heartbeat_deadtime(默认 30s)决定脑裂判定速度。

7.3 仲裁与半数投票

wd_lifecheck_method = 'heartbeat'
enable_consensus_with_half_votes = 'on'
wd_priority = 10        # 10.89.58.7 上;对端配 1

两节点集群默认需要严格多数派,任一台宕机后幸存节点票数不足而无法接管 VIP。实测设置 enable_consensus_with_half_votes = 'on' 后,LEADER 宕机时 STANDBY 以半数票直接升级为 LEADER 并挂载 VIP(约一个 deadtime 周期内完成),旧 LEADER 恢复后以 STANDBY 重新入队——全程无人工干预。wd_priority 在票数相同时决定谁优先成为 LEADER。

7.4 运行验证

show watchdog(SQL)或 pcp_watchdog_info 可观察 LEADER/STANDBY/DEAD 与 VIP 持有者;接管期间用 ip addr show eth0 能看到 eth0:0 上的 10.89.58.100/24 挂载与摘除。VIP 的 ARP 通告依赖 arping_path 指向的 arping 程序,权限上挂载/摘除需要 root 能力(systemd 单元下以 root 运行 pgpool 是常见做法)。

八、在线恢复参数(四坑实测)

8.1 参数组

recovery_user = 'postgres'
recovery_1st_stage_command = 'recovery_1st_stage'

pcp_recovery_node 触发时,pgpool 连接主库执行 pgpool_recovery() 函数,函数在主库 PGDATA 下查找并执行 1st stage 脚本(参数固定顺序:主库 PGDATA、目标主机、目标 PGDATA、主库端口、目标节点号、目标端口、主库主机),完成后自动查找执行 pgpool_remote_start(约定文件名,不占参数位)。前置条件:

  1. 主库安装 pgpool_recovery 扩展(源码 src/sql/pgpool-recovery,PGXS 编译,make USE_PGXS=1 install 后 CREATE EXTENSION pgpool_recovery);
  2. 主库 PGDATA 下部署 recovery_1st_stage 与 pgpool_remote_start(官方样例在 src/sample/,需按实际 PGHOME/SSH 路径改写,chmod 755);
  3. 主库到备库的 postgres 系统用户免密 SSH(专用密钥 id_rsa_pgpool 放 /var/lib/postgresql/.ssh/);
  4. 恢复目标节点的 PostgreSQL 已停止。

8.2 成功序列实测

实测环境(PG17,PGHOME=/usr/local,备库 10.89.58.3)三轮执行 pcp_recovery_node -h 127.0.0.1 -p 9898 -U admin -n 1:

pcp_recovery_node -- Command Successful
 node_id | hostname | port | status | pg_status | role    | pg_role  | replication_delay
    0    |   pg1    | 5432 |   up   |    up     | primary | primary  |
    1    |   pg2    | 5432 |   up   |    up     | standby | standby  |         0

备库 pg.log 关键回显:entering standby mode → consistent recovery state reached → started streaming WAL from primary。恢复脚本内含物理复制槽创建(以目标主机名命名),全程无需手工 pg_basebackup。

8.3 四个真实坑点(后端为 Alpine 系统或官方发行版镜像部署形态时)

以下坑点在 2026-10-20 实测中逐一踩中,若你的 PG 节点是传统 systemd 包部署可跳过本节:

  1. 账户锁定:Alpine 下 postgres 账户 /etc/shadow 密码字段默认 !,OpenSSH 视为 locked,任何认证方式都拒绝,sshd 调试日志表现为 User postgres not allowed because account is locked。修复:字段改为 *(保留锁定密码登录但放行密钥认证)。
  2. StrictModes 拒读 authorized_keys:数据目录父级 /var/lib/postgresql 默认 1777(粘滞位全可写),sshd 报 Authentication refused: bad ownership or modes for directory /var/lib/postgresql。修复:chown postgres:postgres + chmod 755。
  3. VOLUME 挂载点不可删:官方发行版镜像将 PGDATA 声明为数据卷挂载点,恢复脚本样例中 rm -rf $PGDATA 报 Resource busy。修复:改为清空内容——find "$PGDATA" -mindepth 1 -delete。
  4. PGDATA 权限:pg_basebackup 向既有目录写入后目录权限仍为 1777,postmaster 启动 FATAL data directory has invalid permissions ... should be u=rwx (0700) or u=rwx,g=rx (0750)。修复:脚本在 pg_basebackup 后追加 chmod 700 $PGDATA。

8.4 detach 不停库的次生坑

实测确认:pcp_detach_node 只把节点移出 pgpool 池(status 变 down,pg_status 仍 up),不会停止节点上的 PostgreSQL。对这样的节点直接执行 pcp_recovery_node,1st stage 会清空并重建其 PGDATA(旧进程的 pid 文件被删),随后 remote_start 的 pg_ctl 判断「未运行」尝试启动,但 5432 端口仍被旧进程占用,最终报 executing remote start failed。正确顺序:先停节点 PostgreSQL,再 pcp_detach_node(或依赖健康检查摘除),再 pcp_recovery_node。恢复完成后若节点未自动入池,补一次 pcp_attach_node。

九、认证与安全参数

9.1 三份凭据文件

文件内容实测格式
pcp.confPCP 接口账号admin:c62d929e7b7e7b6165923a5dfc60cb56,为 md5(密码) 裸哈希无前缀(与 pool_passwd 的「带 md5 前缀且加盐用户名」不同,源码 src/tools/pcp/ 实证)
pool_passwd前端到后端的密码映射appuser:AESWQ2KKG1ntHerL+GsZtGpEw==(AES-256-CBC)或 user:md5...(md5(密码+用户名))
pool_hba.conf前端接入 ACL语法同 pg_hba.conf,trust/md5/scram 等

.pcppass 口令文件为 4 段式 hostname:port:username:password(通配用 *),文件权限必须 600——实测写成 5 段式时会把第 4、5 段整体当密码导致 PCP 连续认证失败。pgpool 主进程需要对 pcp.conf、pool_passwd 有读权限,apt 安装后默认属主 root:postgres 即可。

9.2 pg_enc:AES 加密 pool_passwd

openssl rand -hex 32 > /etc/pgpool2/pool_key && chmod 600 /etc/pgpool2/pool_key
pg_enc -m -u appuser -k /etc/pgpool2/pool_key -f /etc/pgpool2/pgpool.conf 'secret123'
# 输出:appuser:AESWQ2KKG1ntHerL+GsZtGpEw==
pg_enc -k /etc/pgpool2/pool_key 'secret123'   # 不带 -m 时仅打印密文

实测确认:key 文件为 hex 编码(openssl rand -hex 32 产出 64 位十六进制串);-m 直接把 AES 前缀密文写入 pgpool.conf 中 pool_passwd 指定的文件;后端认证要求为 md5/scram-sha-256 时 pool_passwd 内必须存在对应用户条目,否则后端拒绝。

9.3 TLS

ssl = 'on' + ssl_key/ssl_cert/ssl_ca_cert 一组参数控制前端 TLS;后端方向走 PostgreSQL 自身的 ssl 配置,pgpool 透明转发。

十、日志参数(4.7 变更)

log_destination = 'stderr'
logging_collector = 'on'
log_directory = '/var/log/pgpool'
log_filename = 'pgpool-%Y-%m-%d.log'
work_dir = '/var/log/pgpool'

4.7.0 将旧参数 logdir 更名为 work_dir(存放状态文件:pgpool_status、pgpool.pid 等),旧名实测报 unknown parameter。开启 logging_collector 后 pgpool 才会把 stderr 重定向为按日轮转的文件;实测 pcp_log_rotate 在 collector 关闭时返回 logging_collector disabled(命令篇有原始回执),属于预期行为而非故障。

十一、核心参数速查表

参数默认生产建议备注
num_init_children32按峰值并发 ÷ 复用率排队实测见 §2.2
max_pool42-4与后端 max_connections 相乘
backend_weightN1主库 0(读写分离时)只影响读
load_balance_modeonon系统表/事务例外见 §4.3
memory_cache_enabledoff视热点读比例§5
health_check_period0100 = 关闭,务必开启
backend_clustering_modestreaming_replicationstreaming_replication4.7 新,取代 master_slave_mode
read_only_function_list空count 等只读函数4.7 新,取代 white_function_list
enable_consensus_with_half_votesoff双节点时 on§7.3
recovery_1st_stage_command空recovery_1st_stage配套脚本见 §8
work_dir/var/log/pgpool—4.7 由 logdir 更名

十二、FAQ 与避坑清单

  1. 改了配置不生效:先确认 reload 还是 restart 生效域;show pool_status 可核对运行时值。
  2. SELECT 没走备库:系统表查询、显式事务、VOLATILE 函数、锁定读四类例外(§4.3/§4.4)。
  3. 连接数超限:num_init_children × max_pool 加复制/运维连接别超后端 max_connections;第三个连接排队 6 秒的实测见 §2.2。
  4. watchdog 起不来:按 §7.1-§7.3 四个硬约束逐项核对(pgpool_node_id 文件、hostnameN 含自身、heartbeat 覆盖自身索引、device 非空)。
  5. 在线恢复 remote_start 失败:detach 不停库 + 端口占用(§8.4);Alpine 部署形态四坑(§8.3)。
  6. pcp 认证失败:pcp.conf 用 md5(密码) 裸哈希;.pcppass 四段式且 chmod 600(§9.1)。
  7. pgpool 拒绝启动报语法错误:字符串一律单引号(§1.3)。
  8. 升级到 4.7:master_slave_mode 删除、logdir→work_dir、white/black_function_list 更名,三处参数迁移(§3.1/§4.4/§10)。

十三、参考链接