PostgreSQL 教程: 检查事务 ID 耗尽

五月 12, 2024

摘要:在本教程中,您将学习如何在 PostgreSQL 中检查事务 ID 耗尽。

目录

事务 ID 回卷

大多数人最初意识到这个问题,认为他们需要监控的问题,就是事务 ID 回卷本身,但从技术上讲,事务 ID 的耗尽才是真正的问题。PostgreSQL 在技术上能够很好地处理事务 ID 的回卷。但是,如果达到回卷点,事务 ID 会即将用完,这才是为什么回卷本身会令人担忧的原因。

检查事务 ID 耗尽

以下查询可以提供非常简单的数据,来指示问题的趋势/警报。

WITH max_age AS (
    SELECT 2000000000 as max_old_xid
        , setting AS autovacuum_freeze_max_age
        FROM pg_catalog.pg_settings
        WHERE name = 'autovacuum_freeze_max_age' )
, per_database_stats AS (
    SELECT datname
        , m.max_old_xid::int
        , m.autovacuum_freeze_max_age::int
        , age(d.datfrozenxid) AS oldest_current_xid
    FROM pg_catalog.pg_database d
    JOIN max_age m ON (true)
    WHERE d.datallowconn )
SELECT max(oldest_current_xid) AS oldest_current_xid
    , max(ROUND(100*(oldest_current_xid/max_old_xid::float))) AS percent_towards_wraparound
    , max(ROUND(100*(oldest_current_xid/autovacuum_freeze_max_age::float))) AS percent_towards_emergency_autovac
FROM per_database_stats;

percent_towards_wraparound 指标是设置警报的真正关键指标。由于它使用 age() 函数来确定事务 ID 值,因此它会考虑它们是否真的处于耗尽点,以查看回卷是否是一个真正的问题。如果达到耗尽,数据库将被迫关闭,并可能导致不确定的停机时间,以进行修复。此查询中有一点缓冲,因为它检查的上限(确切地说是 20 亿)小于导致耗尽的实际最大整数值。但它已经足够接近了,应该立即对达到 100% 的警报采取行动。

percent_towards_emergency_autovac 指标是我们建议监控的一个附加值,特别是对于以前从未监控过此指标的系统(请参阅下面有关冻结的近期好处的说明,了解何时可以调低该警报优先级或移除它)。它将监视数据库中达到 autovacuum_freeze_max_age 的最高事务 ID 值。这是一个用户可调的值,默认值为 2 亿,当任何表的最高事务 ID 值达到该值时,在该表上会启动一次更高优先级的自动清理。您可以识别出这个特殊的清理会话,因为在 pg_stat_activity 中,它会被标记为 (to prevent wraparound)。从某种意义上说,它的优先级更高,即使禁用了自动清理,它也会运行,如果手动取消该清理,它几乎会立即再次重新启动。它还需要一些不同的内部低级锁,因此根据它们在紧急清理期间的锁定方式,可能会在这些表上引起稍高的争用。如果您确实遇到争用/锁定问题,并且可以确认问题来源于紧急清理,那么取消它以完成其他事务也是完全安全的。请注意,它会继续重新启动,直到能够成功完成回卷式清理或运行了一次手动清理。

对于每秒事务数很高的数据库,想要避免紧急清理期的频繁出现,增加 autovacuum_freeze_max_age 可能是有益的。增加此值的主要问题是,它可能会增加数据目录下 pg_xactpg_commit_ts 文件夹中的存储空间。同样,请阅读上面链接中的日常清理文档,了解调整此设置时的这些存储要求。一般可以将此值设置为 10 亿,不会有太大问题,但前提是需要确定有在监控回卷并且磁盘空间足够。

修复事务 ID 耗尽

要使最高事务 ID 的 age 值回落,最简单(但不一定是最快)的方法是,强制对整个数据库集群进行一次清理。要实现这种集群范围的清理,最好方法是用 PostgreSQL 附带的 vacuumdb 二进制实用程序。

vacuumdb --all --freeze --jobs=2 --echo --analyze

--all 选项可确保对所有数据库都进行清理,因为事务 ID 是一个全局值。--freeze 选项可确保运行更激进的清理,以确保在该表中冻结尽可能多的元组(有关冻结的详细信息,请参阅日常清理)。--jobs=2 允许并行运行多个清理。这应该设置在系统处理能力的范围内,以加快速度,但要小心设置得太高,因为它会导致额外的 IO 和更快地生成 WAL(增加磁盘使用率)。--echo 只是提供一些很小的反馈,以让您可以看到一些进度。--analyze 确保更新统计信息。如果很在意完成运行清理的时间,则可以将其关闭,稍后使用 --analyze-only 选项作为单独的步骤运行。

冻结的短期好处

在这里要提到的 --freeze 选项的另一个好处是,在未来的清理操作中,可以大大减少 IO 和 WAL 的产生。PostgreSQL 9.6 引入了一项功能,如果页面中的所有元组都已标记为冻结,则 vacuum 能够跳过该页面。PostgreSQL 11 在索引方面对此进行了进一步改进。因此,如果您有很多旧表不再被写入,那么当它们因任何原因需要 vacuum 时,这是一个成本低得多的操作。这也让 percent_towards_emergency_autovac 警报不那么令人担忧,因为它不会产生太多意外的突发活动。因此,一旦你把事情调整好了,你可以把这个警报看作是低优先级的警告,甚至可以删除它,只用担心对回卷本身的监控。

了解更多

PostgreSQL 监控