问题现象
带有备租户的集群在升级过程中,升级部分 Zone 为新版本处于混跑状态下,备租户的可读位点卡住。同时有 transfer 任务卡住,某个迁移任务也一直重试无法成功。
比较直观的报警信息如下。
observer.log.20231212110255325:[2023-12-12 11:02:44.631751] ERROR issue_dba_error (ob_log.cpp:1850) [25877][T1008_ReplaySrv][T1008][Y0-0000000000000000-0-0] [lt=0][errcode=-4388] Unexpected internal error happen, please checkout the internal errcode(errcode=-4023, file="ob_ls_adapter.cpp", line_no=90, info="single replay task retry cost too much time. replay may be delayed")
上述告警持续打印。同时报错日志流是一个 transfer 任务的目的端日志流。
关键诊断信息
触发条件
带有备租户的集群升级混跑阶段,回放日志触发了 transfer 操作,且 transfer 的源端和目的端日志流的成员列表不一致,为保证成员列表一致,源端日志流发起了迁移操作,同时备库已同步到了源端日志流的 block_tx 类型的GC日志。
事前巡检
在升级带有备租户的集群前(升级前的版本为可能出现该问题的版本:OceanBase 数据库 V4.2.0 所有版本以及 V4.2.1 GA 版本),在升级集群前取一个时间点 T1,在 T1后 保证主库尽量不要发起会触发 transfer 的操作比如扩缩容。在备租户的同步位点越过 T1 后,再升级。
事后诊断
如下日志告警持续打印。
observer.log.20231212110255325:[2023-12-12 11:02:44.631751] ERROR issue_dba_error (ob_log.cpp:1850) [25877][T1008_ReplaySrv][T1008][Y0-0000000000000000-0-0] [lt=0][errcode=-4388] Unexpected internal error happen, please checkout the internal errcode(errcode=-4023, file="ob_ls_adapter.cpp", line_no=90, info="single replay task retry cost too much time. replay may be delayed")报错日志流是一个 transfer 任务的目的端日志流。
查看报警线程上下文可以看到该日志流回放一直重试,且是 transfer 相关日志。

同时可通过如下查询确认报错日志流处于 transfer 任务中。
select * from oceanbase.__all_virtual_balance_task where tenant_id=xxx and dest_ls='回放报错重试日志流ID'。示例结果如下。

该查询结果中
src_ls字段展示的是 transfer 源端日志流 ID,记为transfer_src_ls_id。transfer 源端日志流正在进行一个迁移任务,同时迁移目的端 OBServer 为 1 中告警 OBServer。
select * from oceanbase.__all_virtual_ls_replica_task where tenant_id=xxx and ls_id=$transfer_src_ls_id;示例结果如下。

问题原因
带有备租户的集群规模如下所示。
| server | zone | 版本 |
|---|---|---|
| z1.observer0 | z1 | V4.2.3 版本 |
| z1.observer1 | z1 | V4.2.3 版本 |
| z2.observer0 | z2 | V4.2.1 GA 版本 |
| z2.observer1 | z2 | V4.2.1 GA 版本 |
| z3.observer0 | z3 | V4.2.1 GA 版本 |
| z3.observer1 | z3 | V4.2.1 GA 版本 |
其中 z1 升级到 V4.2.3 版本,z2 和 z3 还是老版本 V4.2.1 BP9 GA 版本。1008 租户的两个日志流 1012 和 1001 副本的物理位置如下。
1012:z1.observer0 z2.observer0 z3.observer0 1001: z1.observer1 z2.observer0 z3.observer0
此时备租户回放了一条 transfer 日志,transfer 操作需要保证 1012 的成员列表和 1001 一致,因此需要将 1012 日志流在 z1 上的副本从 z1.observer0 迁移到 z1.observer1 上。该迁移任务的源端选择的是 z2.observer0。
1012 日志流在 transfer 结束后被删了,因此日志流中包含一条 block_tx 的 GC 日志(其 SCN 记为 block_tx_scn),1012 日志流在 z2.observer0 上的副本回放位点会推过 block_tx_scn。同时该副本上的 SSTable 的右边界大于 block_tx_scn。V4.2 版本的迁移流程为了保证数据的连续性,要求迁移目的端的回放位点大于 SSTable 的右边界。但是这个检查在该场景下会失败,因为 z1.observer1 上的迁移目的端副本在回放 block_tx 日志时,需要租户的可读位点越过 block_tx_scn(新版本),而租户的可读位点因 transfer 任务卡无法推进,而 transfer 任务卡的原因是迁移任务一直无法完成,形成了一个依赖环。
问题的风险及影响
该问题会导致备租户同步回放卡住,进而导致备租户同步卡,备租户和主租户的延时越来越大。
影响租户
影响 OceanBase 数据库中的 Oracle 租户,对于 MySQL 租户和 SYS 租户无影响。
影响版本
OceanBase 数据库企业版 V4.2.0 GA(oceanbase-4.2.0.0-100010082023083014)及之后版本、V4.2.1 GA(oceanbase-4.2.1.0-100000182023092722)及之后版本。
解决方法
升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V4.2.1 BP1(oceanbase-4.2.1.1-101000062023103122)及之后版本。
对备租户 transfer 源端日志流的迁移任务中的迁移源端副本发起一次手动冻结,在该副本的
base_scn位点越过block_tx日志的 SCN 后,新的迁移任务就能成功,最终 transfer 任务也能结束,备租户的回放同步恢复正常。
规避方式
在升级带有备租户的集群前(升级前的版本为可能出现该问题的版本:V4.2.0 所有版本以及 V4.2.1 GA 版本),在升级集群前取一个时间点 T1,在该时间点后保证主库尽量不要发起会触发 transfer 的操作比如扩缩容。在备租户的同步位点越过 T1 后,再升级