作者
digoal
日期
2021-02-24
标签
PostgreSQL , freeze
背景
对于PostgreSQL来说, 因为xid目前是32位的, 所以需要循环使用, freeze的动作来完成循环使用xid的工作. 所以 PG 年龄监控, freeze很重要.
自动化freeze开启的情况下却freeze不掉, 可以开启snapshot too old或者人工监测long query, long xact并杀掉导致freeze工作无法降低xid使用水位的问题, 避免freeze不掉的这种情况.
一旦出现数据库说年龄已经到极限了, 需要停止数据库来freeze, (通常这种告警在数据库日志中会不停的打印, 事务结束或者commit的时候也会收到告警). 可以去PG单用户模式执行vacuum freeze修复, 但是修复过程中如果遇到uncommitted xmin %u from before xid cutoff %u needs to be frozen错误,
猜测这个错误可能是在数据库已经不允许执行事务的情况下被回滚的, 所以显示为uncommitted xid. 也可能是bug可以提给社区修复.
紧急情况下可以考虑注释报错的这段代码, 让freeze可以执行下去, 这些存在的未提交的
src/backend/access/heap/heapam.c
```
/
* Process xmin. xmin_frozen has two slightly different meanings: in the
* !XidIsNormal case, it means "the xmin doesn't need any freezing" (it's
* already a permanent value), while in the block below it is set true to
* mean "xmin won't need freezing after what we do to it here" (false
* otherwise). In both cases we're allowed to set totally_frozen, as far
* as xmin is concerned.
/
xid = HeapTupleHeaderGetXmin(tuple);
if (!TransactionIdIsNormal(xid))
xmin_frozen = true;
else
{
if (TransactionIdPrecedes(xid, relfrozenxid))
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg_internal("found xmin %u from before relfrozenxid %u",
xid, relfrozenxid)));
xmin_frozen = TransactionIdPrecedes(xid, cutoff_xid);
/* 这里开始注释掉
if (xmin_frozen)
{
if (!TransactionIdDidCommit(xid))
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg_internal("uncommitted xmin %u from before xid cutoff %u needs to be frozen",
xid, cutoff_xid)));
frz->t_infomask |= HEAP_XMIN_FROZEN;
changed = true;
}
到这里 */
}
```
记得做修复前先备份原始数据文件.
freeze成功后, 正常启动数据库再对报错的表去执行vacuum和freeze
数据库启动后, 建议dump导出数据, restore到一个新的集群.
PostgreSQL 许愿链接
您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.
9.9元购买3个月阿里云RDS PostgreSQL实例
PostgreSQL 解决方案集合
德哥 / digoal's github - 公益是一辈子的事.





