KES V9R2C16实测:64 位事务 ID 之后,回卷预警不再出现

发布时间:2026/9/6 3:08:08
KES V9R2C16实测:64 位事务 ID 之后,回卷预警不再出现 某天晚上十点多一套业务库突然写不进去了。前端请求开始超时待处理的消息一条条堆着应用日志刷的全是插入失败。工程师查看磁盘和连接数都没到上限。ksql 还能连SELECT 也有结果偏偏写入这条路断了。ksql 一进去age(datfrozenxid) 已经逼近回卷保护阈值。autovacuum 一直扫表回收还是推不动。sys_stat_activity 里有个会话停在 idle in transactionxact_start 还是下午。一个批处理程序调外部文件接口接口挂了事务没提交也没回滚。这个会话把 oldest xmin 钉住死元组暂时不能移除。XID 照样涨距离回卷保护阈值的余量越来越小。这台库当时跑的是 KES V9R2C14事务 ID 32 位。32 位 XID 能编码 2^32 个值正常的前后比较窗口约 2^31也就是 20 亿这个量级。判断回卷风险要看当前 XID 与最老未冻结 XID 的事务年龄。年龄逼近回卷保护阈值时系统会限制分配新 XID免得把旧行看成未来事务。这是 32 位编号空间的约束。库没宕业务已经停了。把这个会话 terminatexmin 松开补一轮 freeze写入才恢复。后来看到金仓 KES V9R2C16 的可用性说明里面直接点了这件事。说明书V009R002C0162026 年 8 月 28 日2.3.4支持 64 位事务 IDXID避免因 32 位事务 ID 回收不及时或长事务阻塞导致的业务中断问题。于是我找了 C014 和 C016 两套库查参数、看日志再挂一个长事务试试清理。验证环境两套正式库用来读参数临时实例分批建都在同一台机器上都是 Oracle 兼容模式实例端口用途C014 正式库54322读版本和参数未改配置、未重启C016 正式库54324同上C014 / C016 临时库54325 / 543269 月 4 日跳号实验C014 / C016 临时库54325 / 54326重建9 月 5 日长事务清理对照、预警复测正式库版本信息项目C014C016version()KingbaseES V009R002C014KingbaseES V009R002C016database_modeoracleoracleCatalog202602101202608061ksql 走各自 Server/bin、Server/lib连 127.0.0.1用户 system库名 test。我用 sys_resetwal -x 把 NextXID 调到高位省去累积事务的过程。这次看到了预警差异没有复现最终拒写。C014 的 initdb 不支持 --xid两边都是 initdb 之后再 resetwal起点才对得齐。跳号后两边都因 clog 对应段文件缺失起不来补上 256KB 全零的 sys_xact 段文件才启动。这是人为跳号绕过了正常的 clog 分配跟版本没关系两边表现一样。这次用的是没有生产业务数据的临时实例生产库不要照搬。临时库测完就删了。同一个 NextXIDC014 报回卷预警C016 没有两边 resetwal 到 2146470000txid_current() 都返回这个值。对齐的只是 NextXID 这个数值两边的事务历史和冻结水位并不相同。9 月 4 日连上 C014日志里是WARNING: database kingbase must be vacuumed within 1014764 transactions HINT: To avoid a database shutdown, execute a database-wide VACUUM in that database.template1、template0、security 的余量同样是 1014764。HINT 里的 database shutdown 是预防性提示库并没有停。算余量得带上对应数据库的冻结水位。9 月 5 日复测时我查到 C014 的 datfrozenxid 在启动后发生了变化只拿 2^31 - NextXID 算不准。C016 没有出现 must be vacuumed也没有 shutdown 提示。两边 INSERT 都正常。9 月 5 日复测又跑了一遍告警差异一致system 超级用户和普通测试用户都能写。9 月 4 日还做过第二次 resetwal把 NextXID 抬到 2147478000两边各跑 8 个客户端、每客户端 2000 笔的 kbbench共 16000 笔。跑完 txid_current 都是 2147494002INSERT 仍然成功没有复现拒写。这 16000 笔没有把余量跑完。C014 第一次跳号后日志给的余量是 1014764要走到拒写得继续往上造事务这次没做。判断 C016 的编号空间我靠的是另外三处freeze 三个参数是 int64 类型age(datfrozenxid) 变成 bigintNextXID 没有 epoch 前缀。长事务旧快照不释放两边都清不掉9 月 5 日另建两套临时实例这次不跳号在正常事务编号下做清理对照。向 review_dead 插 1000 行执行 VACUUM FREEZE。会话 A 开一个 REPEATABLE READ 事务读这张表并取到事务 ID然后挂着不动sys_stat_activity 里显示 idle in transaction。会话 B 把这 1000 行删掉并提交再执行VACUUM (VERBOSE, FREEZE) review_dead;两边都留下了 1000 个暂时不能清除的 dead row versions-- C014 DETAIL: 1000 dead row versions cannot be removed yet, oldest xmin: 1150 -- C016 DETAIL: 1000 dead row versions cannot be removed yet, oldest xmin: 1162我结束会话 A 的事务再跑 VACUUM两边都清掉了这 1000 行。第一次 VACUUM 也推进了一部分冻结水位C014 的 relfrozenxid 从 1149 到了 1150。受旧快照限制的那 1000 个 dead row versions要等事务结束后才能清。参数autovacuum_freeze_max_age 默认从 2 亿抬到 100 亿9 月 4 日查到的两套正式库检查点长得不一样。C01454322还是 epoch:xid 格式Latest checkpoints NextXID: 0:1448C01654324这里没有 0: 前缀输出是一个纯数值。参数用这条查SELECT name, setting, boot_val, source, vartype, max_val FROM sys_settings WHERE name IN ( vacuum_freeze_min_age, vacuum_freeze_table_age, autovacuum_freeze_max_age );nameC014 setting / 类型 / 最大C016 setting / 类型 / 最大autovacuum_freeze_max_age200000000 / integer / 200000000010000000000 / int64 / 1152921504606846975vacuum_freeze_min_age50000000 / integer / 100000000050000000 / int64 / 1152921504606846975vacuum_freeze_table_age150000000 / integer / 2000000000150000000 / int64 / 1152921504606846975说明书 2.4.1 列出的这三项参数类型和上限与实测一致。autovacuum_freeze_max_age 的默认值从 2 亿提到 100 亿这个数已经超过 C014 里该参数允许配置的上限 20 亿。三项参数的 setting 与 boot_val 一致source 均为 default。C014 往上限外面写SET vacuum_freeze_min_age 1000000001; ERROR: 1000000001 is outside the valid range for parameter vacuum_freeze_min_age (0 .. 1000000000) SET vacuum_freeze_table_age 2000000001; ERROR: 2000000001 is outside the valid range for parameter vacuum_freeze_table_age (0 .. 2000000000)同样两个值放到 C016SET 都能进去SHOW 分别是 1000000001、2000000001。autovacuum_freeze_max_age 两边都不能热改要重启C016 默认已经是 10000000000。txid_current() 两边都返回 bigint单看返回类型分不出内部宽度。我还对了 NextXID 的 epoch 前缀、freeze 参数的 vartype / max_val以及 age(datfrozenxid) 的类型。最后这一项C014 是 integerC016 是 bigint。两边对照项C014C016正式库 NextXID 格式9 月 4 日0:1448带 epoch 前缀纯数值无 epoch 前缀首次跳号后 txid_current21464700002146470000回卷预警9 月 4 日有日志提示余量 1014764未出现旧快照保持期间的清理1000 个 dead row versions 暂不能移除相同结束旧事务后再次清理成功清除 1000 行相同第二次跳号后 kbbench 16000 笔再 INSERT成功txid 2147494002成功txid 2147494002SET vacuum_freeze_min_age1000000001超出范围成功autovacuum_freeze_max_age 默认20000000010000000000C016 实测到的变化C014 的 XID 年龄有 32 位编号空间的上限。余量耗尽时日志 HINT 提示 database shutdown。实测里两边 NextXID 都是 2146470000C014 报 must be vacuumed within 1014764 transactionsC016 没有这条。freeze 三个参数的可调范围也变了。autovacuum_freeze_max_age 默认从 2 亿提到 100 亿类型从 integer 变成 int64已经超过 C014 的参数上限。vacuum_freeze_min_age 在 C014 上限是 10 亿我写 1000000001 直接报错同样的值在 C016 能设进去。C016 的防回卷冻结年龄上限比 C014 大得多。NextXID 的格式和 age(datfrozenxid) 的类型也变了。C014 的检查点用 epoch:xid 记录 32 位 XID 的轮转C016 的输出没有 epoch 前缀age(datfrozenxid) 从 integer 变成 bigint。长事务仍然会阻塞死元组清理。1000 个 dead row versionsC014 和 C016 都要等会话 A 结束事务才能清掉。C014 的长事务把冻结水位钉住后系统继续分配 XID 会压缩可用余量日志随后开始预警。C016 在这次相同 NextXID 测试中没有出现这条预警。巡检和升级要动的地方巡检脚本迁到 C016age(datfrozenxid) 用 bigint 接阈值别再写死 2 亿或 20 亿。NextXID 的解析也要改C016 没有 epoch 前缀还按冒号拆会取到错值。说明书 2.1.4 针对列出的 Oracle 兼容版模式给出 sys_upgrade 和 dump/restore 两条升级路径。Catalog 号从 202602101 变成 202608061不能只换 Server/bin 就去开 C014 的数据目录。这次 C016 是新 initdb原地升级我没测。长事务还是要查。8 月 31 日在兼容库上造 idle in transaction 会话时我试过取消查询事务没结束终止连接后才回滚。