暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

从PG15 XID64再次跳票说起

连续几天都没真正讨论技术问题了,今天回归一个技术问题的讨论。使用PG数据库以及其衍生的数据库产品的时候,最大的问题是PG的APPEND STORE存储引擎带来的一个副作用-数据副本的可见性问题导致的FROZEN问题。

这个月初有一天半夜就被一个朋友的电话吵醒。自从不接数据库维保的单子之后,我还很少会被半夜的电话铃声吵醒。接起电话后才发现这是一个PG的问题,对方是一个干了十多年的Oracle dba,现在运维的数据库产品越来越杂了,一些PG的问题自然也需要他们来处置。这是一个4个多TB的PG数据库,有些表经常会有大批量数据写入和修改的操作。突然之间今天业务就大规模报错了,经过检查发现是FROZEN的问题导致了数据库不可用。虽然定位了问题,不过他经过观察发现FREEZE进行的很缓慢,周末还有一些数据维护的大型操作要做,很可能周末无法完全恢复。那样周一业务高峰一来,系统就完蛋了。

说实在,对于PG数据库的运维我也是个新手,最近这几年才开始学习,不过好在对于FROZEN问题我还是研究过的。于是,我问了他一些关于AUTOVACUUM和WORK MEMORY设置的参数,他们的数据库上都是用的安装时的默认值,于是我就建议他们加大maintenance_work_mem为2GB,设置autovacuum_work_mem为-1,同时加大autovacuum_max_workers参数。因为他们的服务器配置很高,调整参数后,这个问题很快就解决了。如果各位同学在大型PG数据库上遇到这个问题,可以采取和老白类似的措施去解决。如果你的服务器CPU数量足够多,物理内存足够大,你还可以再加大一些我建议的几个参数,从而更快速的完成FREEZE。

说实在的,相比ORACLE数据库,PG数据库运维起来还是很省心的。只是因为刚刚开始使用PG数据库的时候,大家对数据库的原理不是很了解,因此有些参数设置不够合理,当数据库比较小的时候还不容易出问题,数据库变大之后,各种问题就暴露出来了。

Postgres为了实现MVCC采用了多个元组副本的实现方式,为了管理跨事务的行可见性,它必须为执行写入的每个事务分配唯一的事务ID(XID)。当事务提交时,此XID存储在行中。从该表读取的查询只能看到早于查询事务ID的行。此事务ID使用32位,因此只能支持大约40亿个事务,因此每个ID前后必须有20亿个ID。这意味着,如果XID出现回转,就会影响可见性算法的一致性,导致应该能看到的数据变得不可见。
为了防止这种情况发生,Postgres通过autoavcuum后台过程在做vacuum的时候为所有较旧的行指定一个特殊的XID(称为FrozenXID)。所有带有FrozenXID的行都被视为过去的行,而不考虑XID环绕问题。通常autovacuum是能够很好的完成这个工作的,不过如果VACUUM工作的比较慢,不能赶上写操作产生新事务ID的速度,事务ID可能会接近20亿大关。Postgres通过在事务ID不足100万的情况下关闭以进行维护避免出现数据丢失。在此期间新的数据不能写入,并且可能需要未知的时间才能恢复正常。

如果PG数据库中有较多写很频繁的大表,并且没有优化autovacuum的相关参数,那么FROZEN的问题就很难避免了。

实际上这个问题和前些年影响很大的Oracle SCN HEADROOM问题是类似的。PG早期的时候可能觉得32位的XID已经够用了,哪怕因为可视性问题打了个折扣也完全够用。ORACLE当年也是用32位的SCN,为了确保SCN够用,不会因为回绕而导致数据库出现读一致性的问题,设定了每秒钟SCN最大可增长不超过16K,做这个设计的时候,16K每秒事务数已经够大了,当时的服务器每秒处理一百个事务都十分困难。而随着硬件的不断发展,32位的SCN明显就不够用了,为了解决SCN HEADROOM问题,Oracle也是花了很长时间,首先让每秒钟可推进的SCN数量可调,并将默认值加大。而彻底解决这个80年代遗留下来的大坑的方案是把SCN扩大为64位。

同样,彻底解决PG的FROZEN问题的解决方案是扩大XID为64位。这个问题实际上从10年前就提出了,甚至很多PGER都以为在PG 12我们就能使用上64位的XID了,当时我也看过不少对于PG12正价XID 64的讨论,不过到了PG 14,这个梦想还是没有实现。实际上俄罗斯的postgresqlpro的企业版上已经使用了64位的XID,这个实现是基于他们公司的Alexander Korotkov提供的一个HACKER。根据他们在一些大负载系统上的测试,64位的XID会在业务高峰时避免50%的性能下降。同样脱胎于PG的opengauss中,也已经实现了XID 64。似乎要解决这个问题并不是件特别困难的事情。

去年的这个时候,一则关于PG 15将支持XID 64的消息从社区传播开来,这是将Alexander Korotkov的方案正式并入主线版本。不过随着PG 15发布日期的邻近,我们在PG 15新功能的正式预览中没有看到XID 64的内容。

XID 64已经成为PG社区的两大跳票王之一了,为什么XID 64屡屡跳票呢?这和PG的底层存储引擎是密切相关的。因为在每一个元组中,都有XMAX、XMIN,这些都是32位的,如果要扩展为64位,必然会引发大量PG代码的修改。因此最好是不动元组的数据结构来实现XID的扩容。从PG 64位XID实现方式的Alexander Korotkov方案上,我们可以看出PG核心研发在这方面的坚持:首先将XID修改为64位;其次磁盘TUPLE结构不修改(HeapTupleHeader结构),XMIN/XMAX依然保持32位,被称为ShortTransactionId,在页头上解决XID的另外32位问题,XMIN/XMAX里保存的是XID的OFFSET部分,而PAGE HEADER里存储XID的BASE;最后内存中的元组从PAGEHEADER中获得XID的BASE部分内容。

根据PG社区的反馈,这回是因为UPSTREAM与XID 64方面的兼容问题无法在PG 15发布前完成适配,才导致XID 64再次与用户失之交臂。根据PG社区的消息看,XID 64在PG 16上是肯定能够和大家见面的,希望这回PG社区不要再跳票了。

从XID 64这个事情,我们也看到了数据库研发的复杂性,如果是在一个MIS项目里,调整某个关键主键的长度,哪怕涉及的业务太复杂,也不至于十年不成。这回PG社区因为一个数据复制组件的兼容性问题而撤回64-BIT XIDS,是一种十分严谨的做法。数据库的问题是会导致应用与数据错误的,而在数字化时代,数据错误可能的后果会相当严重。

即使PG社区有如此严谨的态度,仍然无法避免一些较为严重的BUG随着版本发布。最近发现的PG 14.1到PG 14.3的在线创建/重建索引出现数据错误的严重BUG就是一个例子。如果关键的业务系统上出现这种错误,可能会造成业务错误。

数据库研发时十分严谨的工作,在数字化时代,用户敢在业务系统中使用你的数据库实际上是把企业的业务发展前景捆绑在你的产品上了,因此用户不得不慎重。所以说,我一直对二三十条枪就可以干一个通用关系型数据库的说法不太认可。一个数据库企业要真的是对用户负责,高水平的测试人员都不不应该少于三五十人吧,否则我们就只能把用户当成测试人员了。


点击此处阅读原文
文章转载自开源软件联盟PostgreSQL分会,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论