本文主要介绍 OceanBase 数据库 V4.x 版本 RS 端合并卡住问题的排查步骤。
RS 端合并概览
在介绍 RS 端合并问题卡住排查步骤之前,先简要介绍 RS 端合并的职责,以及 RS 端合并卡住的现象。
RS 端合并的职责
RS 端合并的职责主要包括两个方面。一方面,RS 端负责发起合并;另一方面,RS 端负责判定合并结束。接下来,逐一阐述 RS 端发起合并和判定合并结束的主要流程。
RS 端发起合并的主要流程
duty_time触发每日合并,或者手动执行ALTER SYSTEM MAJOR FREEZE;命令触发合并。生成新的
frozen_scn并插入__all_freeze_info内部表。更新
__all_merge_info内部表的frozen_scn。更新
__all_merge_info内部表的global_broadcast_scn,并将merge_status置为 merging。更新
__all_zone_merge_info内部表的frozen_scn和broadcast_scn,将is_merging置为 true。
RS 端判定合并结束的主要流程
检查每个 Zone 中的 tablet (具体来说,是
__all_tablet_meta_table表中的tablet,附带永久下线 server 过滤条件,以及 locality 过滤条件) 版本号是否皆已推高至当前合并版本号,如果是,则更新__all_zone_merge_info内部表中对应 Zone 的last_merged_scn并将is_merging置为 false。对所有 schema 中的 table 进行副本间 checksum 校验、主表与索引表间 checksum 校验、主备租户 checksum 校验。
成功完成上述二个过程之后,更新
__all_merge_info内部表中的last_merged_scn并将merge_status置为 idle。
RS 端合并卡住现象
通过登录系统租户并查看 CDB_OB_MAJOR_COMPACTION 视图。该视图展示所有租户的合并状态信息。

如上图所示,LAST_SCN 表示上一轮已完成合并的版本号,GLOBAL_BROADCAST_SCN 表示当前这一轮全局广播的合并版本号。当 LAST_SCN == GLOBAL_BROADCAST_SCN 时,表示当前轮次的合并已经结束。当 LAST_SCN != GLOBAL_BROADCAST_SCN 时,表示当前轮次的合并尚未结束。若长时间合并未结束,则可能是合并卡住了。
值得注意的是,若 IS_ERROR == YES,则表示存在 checksum error。在存在 checksum error 的情况下,合并卡住是正常的,需要解决 checksum error 问题之后,才能继续进行合并。具体来说,可以从 CDB_OB_TABLET_CHECKSUM_ERROR_INFO 和 CDB_OB_COLUMN_CHECKSUM_ERROR_INFO 两个视图中查看存在 checksum error 的 tablet 或 table,然后进一步排查导致 checksum error 的原因。除此之外,若 IS_SUSPENDED = YES,则表示已暂停合并。在暂停合并的情况下,合并卡住是正常的,需要通过执行 alter system resume merge 命令手动恢复合并之后,才会继续进行合并。
如果合并长时间未结束,可能出现合并卡住的情况。长时间合并未结束可能由 checksum error 或合并暂停导致。在这种情况下,需要解决 checksum error 问题或通过执行alter system resume merge; 命令恢复合并。
RS 端合并卡住排查步骤
上一节介绍了 RS 端发起合并和判定合并结束两个部分的主要流程,以及 RS 端合并卡住的现象。RS 端合并卡住,通常卡在判定合并结束的流程。判定合并结束的流程包括两个阶段,其一,检查 tablet 版本号是否皆已推高至当前合并版本号;其二,对所有 table 进行 checksum 校验。相应地,RS 端合并卡住,一类是卡在检查 tablet 版本号是否皆已推高至当前合并版本号阶段,另一类是卡在对所有 table 进行 checksum 校验阶段。接下来,介绍如何定位遇到的合并卡住是卡在哪一个阶段。
判断是否卡在检查tablet版本号阶段
本节介绍判断合并是否卡在检查 tablet 版本号阶段的方法,包括查看诊断信息、查看关键日志和查看堆栈信息三种方法。
方法一:查看诊断信息
登录系统租户,通过以下 SQL 语句,查看 __all_virtual_compaction_diagnose_info 表中的合并诊断信息。
## 将 xxx 替换为合并卡住的租户的 ID 号。
select * from __all_virtual_compaction_diagnose_info where tenant_id = xxx;

若存在如图 2 所示,当查询 __all_virtual_compaction_diagnose_info 表输出结果中存在 status = RS_UNCOMPACTED 的诊断信息,则表明还存在 tablet 版本尚未推高至当前合并版本号。也就是说,RS 端合并卡在检查 tablet 版本号是否皆已推高至当前合并版本号阶段,需要进一步排查 存储层 为何尚未将这些 tablets 的版本推高至当前合并版本号。
方法二: 查看关键日志
由于合并服务注册在每个租户 1 号日志流的 Leader上,相关日志自然也就在租户 1 号日志流 Leader 所在的机器上。因此,想查看相关日志,需要先找到租户 1 号日志流 Leader 所在的机器,具体步骤如下:
登录系统租户,找到合并卡住的租户的 1 号日志流切主历史。从切主历史中,找到需要排查的时间段内,租户的 1 号日志流的 Leader 在哪台机器上。大多数情况下,需要排查的是当前时间为什么合并仍未结束,因此只需要找到当前时间,租户的 1 号日志流的 Leader 在哪台机器上即可。
租户 1 号日志流切主历史信息。
## 将 $tenant_id 替换为合并卡住的租户的 ID SELECT gmt_create,svr_ip,svr_port,event,name3,value3 FROM __all_server_event_history WHERE module="ELECTION" AND value1=$tenant_id AND value2=1 ORDER BY gmt_create;
如上图所示,注意红框中的信息
leader prepare to chang leader : "xxx:xxx:xxx:xxx:1028" -> "xxx:xxx:xxx:xxx:1033", reason : ZONE PRIORITY可知当前 Leader 在 IP 地址为 xxx:xxx:xxx:xxx:1033 这台 OBServer 上,因此,在 IP 地址为 xxx:xxx:xxx:xxx:1033 这台 OBServer 上查看对应的日志目录下相应的日志。登录对应机器,并进入对应日志目录后,执行以下命令,查看是否存在
replica not merged...相关日志。若存在,则表明依然存在 tablet 版本尚未推高至当前合并版本号。## 将 xxx 替换为对应的时间。 grep "replica not merged to target version or status not match" rootservice.log.xxx如下图所示,replica not merged 日志。1002 租户存在 1001 号日志流 200001 号 tablet 的版本尚未推高至当前合并版本号。

此外,登录对应机器,并进入对应日志目录后,还可以执行以下命令,查看是否存在
unmerged_count=...相关日志。若存在,则表明依然存在 tablet 版本尚未推高至当前合并版本号。如图 5 所示,11:06:52,1002 租户,z1中还有 163434 个 tablet 副本版本尚未推高至当前合并版本号,z3中还有 155841 个 tablet 副本版本尚未推高至当前合并版本号。## 将 yyy 替换为对应的时间,将 xxx 替换为对应租户的 ID 号。 grep "check updating merge status" rootservice.log.xxx | grep Txxx
图 5,check updating merge status 日志。
方法三:查看堆栈信息
若上述两种方法都找不到任何相关的信息,则可以查看堆栈信息,具体方法如下所示。若堆栈信息中存在 ObMajorMergeProgressChecker::check_tablet_compaction_scn 关键信息,则表明当前处于检查 tablet 版本号是否皆已推高至当前合并版本号阶段。
## 1. 打印堆栈信息
obstack $(pidof observer) > ~/stackinfo
## 2. 查看堆栈信息
vim ~/stackinfo
## 3. 搜索 Txxx_MergeSche 线程,其中 xxx 为合并卡住的租户的 ID 号。
/Txxxx_MergeSche + 回车
注意
可反复多查看几次堆栈信息。若长时间处于检查 tablet 版本号是否皆已推高至当前合并版本号阶段,则需进一步排查原因(例如,是否 tablet 数量太多、是否存在慢 SQL 等)。
判断是否卡在对所有 table 进行 checksum 校验阶段
本节介绍判断合并是否卡在对所有 table 进行 checksum 校验阶段的方法,包括查看关键日志和查看堆栈信息两种方法。
方法一:查看关键日志
与 判断是否卡在检查 tablet 版本号阶段中的方法二查看关键日志 一节中介绍的方法类似,先找到租户 1 号日志流 Leader 所在的机器。然后,登录对应机器,并进入对应日志目录后,执行以下命令,查看是否存在 exists unverified tables... 相关日志。若存在,则表明依然存在 table 尚未完成 checksum 校验。如图6所示,1004 租户存在 506674 号 table 和 736983 号 table 尚未完成 checksum 校验。
# 将 yyy 替换为对应的时间,将 xxx 替换为对应租户的 ID 号。
grep "exists unverified tables" rootservice.log.yyy | grep Txxx

图 6,exists unverified tables 日志。
当存在尚未完成 checksum 校验的 table 时,需要进一步排查未完成 checksum 校验的原因。一方面,可以根据 trace_id 继续搜索相关日志,看是否是由于其它报错引起的。另一方面,需要基于对源码细节的了解,思考是否是 checksum 校验的代码逻辑存在漏洞。
方法二:查看堆栈信息
若上述方法找不到任何相关的信息,则可以查看堆栈信息,具体方法同 判断是否卡在检查 tablet 版本号阶段中的方法三查看堆栈信息 一节。若从堆栈信息中可以看到 ObChecksumValidatorBase::validate_checksum,则表明当前处于对所有 table 进行 checksum 校验阶段。注意,可反复多查看几次堆栈信息。若长时间处于对所有 table 进行 checksum 校验阶段,则需进一步排查原因(例如,是否 tablet 数量太多、是否存在慢 SQL 等)。
更多信息
备租户合并卡住问题
OceanBase 数据库 V4.1 版本开始支持租户级主备库功能。相应地,在合并服务方面,从 OceanBase 数据库 V4.1 版本开始支持备租户合并服务。简单来说,备租户会根据从主租户同步过来的 freeze_info,自动发起合并,并根据从主租户同步过来的 checksum 信息进行主备租户 checksum 校验。除了发起合并的方式和 checksum 校验的内容与主租户有所区别,其他的流程基本与主租户保持一致。 通常来说,备租户合并的完成会晚于主租户合并的完成。这是因为,备租户需要等到从主租户同步到所有的 checksum 信息之后,才能完成 checksum 校验,进而完成整个合并。因此,一般来说,只有当主租户某个版本的合并已经完成情况下,备租户这个版本的合并还卡住的时候,才需要排查备租户合并卡住的原因。 在主租户已完成合并,而备租户合并卡住的情况下,可先确认 __all_tablet_checksum 表中的 checksum 数据,是否尚未从主租户到备租户(若尚未同步,则表明日志同步存在问题,需要进一步排查日志同步的问题。这种情况下,备租户合并卡住是预期内的;若已同步,则表明日志同步不存在问题,需要进一步排查备租户合并的问题)。确认 checksum 数据是否已同步的具体步骤如下:
首先,登录主租户,通过以下 SQL 语句,确认主租户是否已经将 1 号日志流 1 号
tablet对应的checksum写入到__all_tablet_checksum中。如图 7 所示,对于版本号为1678998926807067652的合并,主租户已经将 1 号日志流 1 号tablet的checksum写入__all_tablet_checksum中。## 将 xxx 替换为备租户卡住的合并版本号。 SELECT * FROM __all_tablet_checksum WHERE tablet_id = 1 and ls_id = 1 and compaction_scn = xxx;
图 7,主租户
__all_tablet_checksum内部表中已写入 1 号日志流 1 号 tablet 的checksum。其次,登录备租户,通过以下 SQL 语句,确认备租户
__all_tablet_checksum表中是否尚未从主租户同步到 1 号日志流 1 号 tablet 对应的checksum。如图 8 所示,对于版本号为1678998926807067652的合并,备租户尚未从主租户同步到 1 号日志流 1 号 tablet 的checksum。## 将 xxx 替换为备租户卡住的合并版本号 SELECT * FROM __all_tablet_checksum WHERE tablet_id = 1 and ls_id = 1 and compaction_scn = xxx;
图 8,备租户
__all_tablet_checksum内部表中尚未同步到 1 号日志流 1 号 tablet 的checksum。最后,根据 判断是否卡在检查 tablet 版本号阶段中的方法二查看关键日志 一节中介绍的方法,先找到备租户1号日志流leader所在的机器。然后,登录对应机器,并进入对应日志目录后,执行以下命令,查看是否存在“can not check cross-cluster checksum now, please wait until first tablet...”相关日志。若存在,则表明依然存在checksum数据尚未从主租户同步到备租户。如图9所示,1004租户存在checksum数据尚未从主租户同步到备租户。
# 将 yyy 替换为对应的时间,将 xxx 替换为对应租户的ID grep "can not check cross-cluster checksum now, please wait" rootservice.log.yyy | grep Txxx
图 9,
checksum数据尚未从主租户同步到备租户。
long time no major freeze, please check it 问题
出现 long time no major freeze, please check it 大致有以下几种可能的原因。
每日合并与 DDL 冲突,导致未发起每日合并。
主租户
__all_freeze_info内部表尚未同步到备租户__all_freeze_info内部表
合并相关配置项
| 参数名 | 含义 | 级别 |
|---|---|---|
| enable_major_freeze | 整个集群的合并总开关 | 集群级 |
| major_freeze_duty_time | 每个租户的每日合并开关和具体时间 | 租户级 |
| merger_check_interval | ObMajorMergeScheduler 线程执行 update_merge_status 连续失败3次之后的 idle 时长 |
租户级 |
适用版本
OceanBase 数据库 V4.x 版本。