监控 XID 回卷风险

本页目录

事务 ID 和组事务 ID 的回卷问题是 Postgres 数据库中最严重的事件之一。著名的案例包括:

一些有价值的参考资源:

每个监控设置必须包含两类特定的指标 (以及适当的警报):

  1. 非冻结元组中使用的最老 XID 和 MultiXID (又称 MultiXact ID) 值
  2. 监控 xmin 视界

在这里我们讨论第一类。

32位事务ID

XID 和 MultiXact ID 都是 32 位的,所以总的空间大小为 2^32 ≈ 42 亿。但由于使用了取模算术的原因,XID 有一个"未来"的概念 — 空间的一半被认为是过去的,另一半是未来的。因此,我们需要监控的容量是 2^31 ≈ 21 亿。

来自维基百科的一个例子:Wikipedia "wraparound and freeze":

Wraparound and freeze

为了防止 XID/MultiXID 回卷,autovacuum 进程除了其他任务之外,还会定期执行"冻结"操作,将老的元组标记为已冻结,表示这些元组是属于过去的。

因此,监控元组的 XID/MultiXID 年龄对于控制回卷风险至关重要。

XID和MultiXID回卷风险监控

最常见的监控方法是:

此外,还应检查 MultiXact ID 回卷的风险 (在监控工具中这通常会缺失):

集群级别的高层次监控查询 (数据库级别) 示例:

SQL
with data as (
  select
    oid,
    datname,
    age(datfrozenxid) as xid_age,
    mxid_age(datminmxid) as mxid_age,
    pg_database_size(datname) as db_size
  from pg_database
)
select
  *,
  pg_size_pretty(db_size) as db_size_hr
from data
order by greatest(xid_age, mxid_age) desc;

特定数据库中的表级监控查询,TOP 25:

SQL
with data as (
  select
    format(
      '%I.%I',
      nspname,
      c.relname
    ) as table_name,
    greatest(age(c.relfrozenxid), age(t.relfrozenxid)) as xid_age,
    greatest(mxid_age(c.relminmxid), mxid_age(t.relminmxid)) as mxid_age,
    pg_table_size(c.oid) as table_size,
    pg_table_size(t.oid) as toast_size
  from pg_class as c
  join pg_namespace pn on pn.oid = c.relnamespace
  left join pg_class as t on c.reltoastrelid = t.oid
  where c.relkind in ('r', 'm')
)
select *
from data
order by greatest(xid_age, mxid_age) desc
limit 25;

告警

如果 XID 或 MultiXID 的年龄增长超过一定的阈值 (通常为 2 亿,参考 autovacuum_freeze_max_age),这表明某些东西阻碍了正常的 autovacuum 工作。

因此,根据 autovacuum 的设置,监控系统应配置为在 XID 和 MultiXID 年龄超过预定义阈值 (通常在 3 亿到 10 亿范围内) 时发出警报。年龄超过 10 亿应被视为危险信号,要求紧急缓解措施。

讨论与补充

在 GitHub 查看讨论

支持作者

感谢支持 PostgreSQL Howto 的长期维护。

微信赞赏码

读者交流群

二维码若已过期,可通过公众号 PostgreSQL 学徒或邮件联系。

PostgreSQL 学徒读者交流群二维码