一月 29, 2026
摘要:在本教程中,您将学习如何在 PostgreSQL 中检查备用服务器上长时间运行的事务。
目录
启用 hot_standby_feedback 的备用服务器上的查询
在启用了hot_standby_feedback 的流式复制架构中,备库上执行的查询会阻止主库上的 VACUUM 操作回收死元组。这是设计使然:hot_standby_feedback的存在目的就是防止VACUUM删除死元组,进而避免备库出现查询冲突。
搭建流式复制环境,修改配置文件postgresql.conf,在备库上启用hot_standby_feedback配置项,并减小wal_receiver_status_interval的值,以此提高备库向主库发送反馈的频率。
hot_standby_feedback = on
wal_receiver_status_interval = 1s
在备库上,启动一个事务并执行查询。
BEGIN;
SELECT pg_sleep(300);
pg_sleep
----------
(1 row)
注意:我们使用
pg_sleep()函数来防止查询完成后快照被立即释放。你也可以将事务隔离级别设置为REPEATABLE READ,从而在事务内维持该快照的有效性。
在主库上执行数据删除操作,然后运行VACUUM命令。
DELETE FROM t;
VACUUM (verbose) t;
INFO: 00000: vacuuming "postgres.public.t"
INFO: 00000: finished vacuuming "postgres.public.t": index scans: 0
pages: 0 removed, 1 remain, 1 scanned (100.00% of total), 0 eagerly scanned
tuples: 0 removed, 100 remain, 100 are dead but not yet removable
removable cutoff: 831, which was 1 XIDs old when operation ended
frozen: 0 pages from table (0.00% of total) had 0 tuples frozen
visibility map: 0 pages set all-visible, 0 pages set all-frozen (0 were all-visible)
index scan not needed: 0 pages from table (0.00% of total) had 0 dead item identifiers removed
avg read rate: 0.000 MB/s, avg write rate: 0.000 MB/s
buffer usage: 12 hits, 0 reads, 0 dirtied
WAL usage: 0 records, 0 full page images, 0 bytes, 0 full page image bytes, 0 buffers full
memory usage: dead item storage 0.02 MB accumulated across 0 resets (limit 64.00 MB each)
system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
日志信息tuples: 0 removed, 100 remain, 100 are dead but not yet removable表明死元组未被回收。而日志removable cutoff: 831, which was 1 XIDs old when operation ended则说明,事务号 831 是导致该现象的根源。
启用 hot_standby_feedback 的备用服务器和 VACUUM
通常,PostgreSQL 可以在一个行版本对任何事务不可见时立即清理该行。如果在带有一个备用节点的主节点上运行 PostgreSQL,在主节点上 VACUUM 要清理的行版本,可能是备用节点上的查询所需要用到的。这种情况叫做“复制冲突”,当检测到冲突时,备用节点上的查询会被取消掉。
为了防止备用节点上的查询因复制冲突而被取消,您可以将 hot_standby_feedback 设置为 on,这可以让备用服务器告知主服务器在其上面运行的最老事务。这样,主服务器可以避免清理备用服务器上的事务仍在使用的行。
但是,将hot_standby_feedback设置为 on,也意味着,备用服务器上长时间运行的查询,能够阻止主服务器上的行被清理。
列出备用服务器上的长事务
要查找所有备用服务器的xmin,可以在主服务器上运行下面的查询:
SELECT pid, application_name, client_addr, state, backend_xmin
FROM pg_stat_replication
WHERE backend_xmin IS NOT NULL
ORDER BY age(backend_xmin) DESC;
一旦确定了备用服务器,您可以通过运行下面命令,找到备用服务器中持有该xmin水位线的查询,及其连接对应的 pid:
SELECT pid, datname, usename, state, backend_xmin, backend_xid
FROM pg_stat_activity
WHERE backend_xmin IS NOT NULL OR backend_xid IS NOT NULL
ORDER BY greatest(age(backend_xmin), age(backend_xid)) DESC;
若要避免由于备用服务器上长时间运行的事务而导致主服务器过度膨胀,可以采用以下方法之一:
- 继续处理复制冲突,并将
hot_standby_feedback设置为 off。 - 将 vacuum_defer_cleanup_age 设置为一个更高的值,以便将主服务器上的行的清理推迟到
vacuum_defer_cleanup_age数量的事务处理结束后,从而为备用服务器上的查询提供更多的时间来完成,而不会遇到复制冲突。 - 最后,您还可以跟踪和终止备用数据库上长时间运行的查询,就像我们在对主服务器检查长时间运行的事务教程中讨论的一样。