首批通过分布式安全可靠测评,为关键业务系统打造
如何排查合并卡住问题
更新时间:2025-10-22 08:12
在 OceanBase 数据库 V4.x 版本中,关于下文中涉及的内部表 __all_tablet_meta_table 的 snapshot_version 字段存在于 OceanBase 数据库 V4.0.0 版本,从 OceanBase 数据库 V4.1.0 版本开始,调整 为 compaction_scn。
本文以 OceanBase 数据库 V4.x 版本进行介绍。
RS 层的 major freeze
首先查看系统表以及 RS 层合并发起的情况。
查看当前各个租户的合并状态
在系统租户下,通过查看 CDB_OB_MAJOR_COMPACTION 视图,可以查看各个租户的合并状态。

在上面的截图中,LAST_SCN 表示上一轮已完成合并的版本号,GLOBAL_BROADCAST_SCN 表示当前这一轮合并的版本号,只有当 LAST_SCN == GLOBAL_BROADCAST_SCN 时,表示当前轮次的合并结束。
如果 STATUS 列一直出于 COMPACTING 状态,则说明该租户的合并可能卡住了。另外,也可以关注下 IS_ERROR 列,如果该列的值为 CHECKSUM_ERROR,则说明该租户下出现了 checksum 校验不一致的问题。
排查是哪个/哪些 tablet 未合并到指定版本
合并判定结束的逻辑,是查看该租户下所有的 tablet (过滤掉一些不符合需求的)是否已合并到指定版本号。只要有一个 tablet 没有合并到指定版本,则该租户的合并就不会结束。因此,需要查看该租户下哪些 tablet 没有合并到指定版本。
通过以下两种方式来查询:
直接查内部表
__all_tablet_meta_table,查询所有compaction_scn未达到指定版本号的 tablet。
在 RS Leader 所在的 OBServer 上去查看日志,基于
replica not merged关键字。
通过搜索 1004 租户相关的日志,可以得到如下图所示的结果。

可以发现,1004 租户下,
tablet_id=50002的 tablet,长时间(一般超过 10 分钟)处于A=1655899935260047146版本,而没有合并到指定的B=1655900220014778135版本。
确认 tablet 信息
如果上述是通过采用查日志的方式排查,则需要确认该 tablet 在内部表中的 compaction_scn 信息是否真的未合并到指定版本 B。
__all_tablet_meta_table 存在于 SYS/META 租户下:比如要查 1004 租户下的某个 tablet,需要先切至其 META 租户才能查到 1004 的 tablet meta 信息。先切到指定租户下去,然后查询指定 tablet,如下图所示。

通过上述查询可以确认,该 tablet 的 compaction_scn 确实是老版本号 A,没有合并至所需的 B 版本。
meta 表目前实现了对应的虚拟表 __all_virtual_tablet_meta_table,因此确认 tablet 信息时不需要再去切换租户了。

存储层的 tablet major_merge
至此,需要去查看存储层相关的问题,来排查为什么该 tablet 没有合并至指定版本。
确认存储层 tablet 合并调度正常
定位到未完成合并的 tablet 后,需要先确认这个 tablet 的合并调度是否正常。 合并未调度的原因有很多:由于合并前需要做一次转储,保证 tablet snapshot version 推过合并冻结点,所以如果转储存在问题,则会导致 tablet 的合并无法被调度。
指定 tablet,查看 __all_virtual_compaction_diagnose_info:

从上图可以看出,549755813987 这个 tablet 的 MAJOR MERGE 处于 NOT_SCHEDULE 状态,原因是 tablet snapshot version 未推过合并冻结点。
tablet snapshot version 未推过合并冻结点的原因也有多个:
备机读时间戳未推过合并冻结点,此时无法发起转储,合并也就无法调度。
转储失败。
当前转储队列压力较大,转储 DAG 一直未调度,导致合并超时。
memtable 未达到冻结条件(未打印 flush memtable 日志)。
从上图可以看出,tablet 549755813987 的 MINI MERGE 处于 FAILED 状态,说明该 tablet 合并卡住的原因是转储失败了。
寻找相关 Trace
一般来说,如果是转储/合并失败,失败原因及 trace ID 都会记录到 __all_virtual_dag_warning_history 虚拟表中。
指定 tablet,查看 __all_virtual_dag_warning_history:

成功拿到 trace ID,接下来就可以参考 gmt_modified,到对应时间范围内的 observer log 中查看具体的失败原因了。
NOTICE
RS 端的 major freeze 实际包括两个过程:判定租户下所有 tablet 的 major merge 已完成;checksum 校验。
当 RS 端判定 tablet 的 major merge 完成后,开始执行 checksum 校验工作,主要包括 tablet 三副本间的 data_checksum 校验,主表与索引表之间的 column_checksum 校验。因此,如果出现 OB_CHECKSUM_ERROR,则说明合并实际已完成,ckm 校验失败。
对于任一租户而言,如果其 checksum 校验失败,则不允许其发起下一轮的 major freeze。
除非在解决了数据一致性问题后,通过
alter system clear merge error来清除 checksum_error 状态。RS 主要通过扫描各租户的
__all_tablet_meta_table来判断合并是否完成。因此如果是汇报出了问题/ observer 下线了,导致 meta 表没被更新,也会导致合并状态无法结束。可以通过执行以下 SQL 来快速确认这种情况:
select * from __all_virtual_server_compaction_event_history where tenant_id = XXX and compaction_scn = XXX and event like '%FINISHED%';
关键日志
如果 farm 遇到了合并问题,可以通过搜一些关键性日志来定位问题:
搜索
rootservice.log,定位未成功合并的分区。
在定位到未合并的分区后,可以搜索以下日志定位未合并原因。
确认 Tablet 对应租户是否发起了版本号为
broadcast_scn的合并。FLOG_INFO("try to schedule merge", K(tenant_id), K(merge_info.broadcast_scn_), K(scheduler_frozen_version));如果未找到该日志,说明是 RS 未对该租户调度合并。此时可以搜索
refresh merge info:
确认合并前的转储 memtable 是否冻结。
TRANS_LOG(INFO, "ready for flush", K(bool_ret), K(ret), K(current_right_boundary), K(ls_id), K(*this)); TRANS_LOG(INFO, "flush memtable", K(ret), K(param), KPC(this));如果有日志,需要确认 memtable 的 snapshot version 是否大于本次合并的版本号,如果小于,则说明备机读时间戳没有推过冻结点。

没有日志,说明 memtable 没有冻结。
确认转储/合并是否成功。
// 日志量少的话,可以直接搜这条日志,用 Tenant ID 和 Tablet ID 过滤后,检查是否有失败的转储和合并 DAG grep "dag_ret:-" observer.log | vi - // 检查转储是否成功生成了对应的转储/合并 sstable grep "sstable merge finish" observer.log | vi -
适用版本
OceanBase 数据库 V4.x 版本。