首批通过分布式安全可靠测评,为关键业务系统打造
死锁检测功能不完整
更新时间:2026-06-12 03:56
问题现象
用户 SQL Hang 死,经分析存在业务逻辑上的 SQL 死锁,但是 OceanBase 数据库没有自动杀掉死锁中的某一个事务解除环状依赖导致死锁一直持续。
关键诊断信息
触发条件
列出两个比较可能出现的场景(但由于这个问题的复杂性,还有其他可能的情况)。
场景 A:行锁的 Holder 信息被误清除(OceanBase 数据库 V4.x 之后版本会发生)
业务开启了事务 A,内部执行的多条 SQL 修改同一行 a 多次(生成多个 MVCC trans node),此时内部记录了行 a 的 hash 到 txid 的映射关系。
事务 A 可能回滚一部分 trans node(rollback to savepoint),此时清理了内部行 a 的 hash 到 txid 的映射关系。
事务 B 修改事务 A 修改过的行,与事务 A 冲突,并且由于未触发转储未提交,冲突发生于 MemTable 中,而非 SSTable 中,冲突发生后,事务 B 进入 LockWaitMgr 的锁等待队列,此时标记该事务 B 等待行 a(具有动态等待关系,即动态获取行 a 的 Holder)。
由于行 a 的 Holder 信息在第 2 步被误清除,因此事务 B 在检测死锁时无法构建 WFG(wait-for-graph,等待关系图),从而无法检测成功。
引发该场景下问题的本质原因是死锁检测维护的 Holder 信息从行锁相关事件(行锁没有多版本)变为 trans node 相关事件(多版本)之后,没有维护 Holder 的多版本信息。
场景 B:锁冲突与切主并发(OceanBase 数据库 V3.x/V4.x 均会发生)
业务开启了事务 A,修改行 a,记录了行 a 的 hash 到 txid 的映射关系。
修改行 a 所在的【分区(OceanBase 数据库 V3.x 版本)/tablet 所在的日志流(OceanBase 数据库 V4.x 版本)】的 Leader 从机器 1 转移到机器 2。
机器 1 上的事务 A 将会执行卸任动作,清除行 a 的 hash 到 txid 的映射关系,机器 2 上的事务 A 将会执行上任动作,但【不会】记录行 a 的 hash 到 txid 的映射关系。
事务 B 修改行 a,与场景A中第3步发生的事情相同,但无法在机器 2 上获取行 a 的 Holder 信息因为并未被记录。
引发该场景下问题的本质原因是事务上任不允许遍历 callback,因为大事务遍历 callback 的动作代价过大,当前是保大事务,放弃死锁检测。
事前巡检
无需巡检。
事后诊断
在业务死锁持续的过程中如果能发现 observer.log 中持续刷如下日志,则说明撞到了死锁检测的 bad case。
[2023-12-21 20:16:10.932082] WDIAG [DETECT] get_resource_from_callback_list_ (ob_lcl_node.cpp:416) [86323][T1004_DetectorT][T1004][Y0-0000000000000000-0-0] [lt=26][errcode=-4018] execute user callback failed(ret=-4018, ret="OB_ENTRY_NOT_EXIST", *this={this:0x7f68f6eac030, self_key:{txid:17619}, parent_key:invalid key, timeout_ts:"2024-04-15 14:02:46.674498", lclv:1, private_label:{addr:"127.0.0.1:xxxxx", id:5570, priority:{priority_range:0, priority_value:18445040919938162755}}, public_label:{addr:"127.0.0.1:xxxxx", id:5570, priority:{priority_range:0, priority_value:18445040919938162755}}, detect_callback:{this:0x7f68f6eac220, base:0x7f68f6eac230, &allocator_:0x55d48689a980, &DEFAULT_ALLOCATOR:0x55d48689a980}, auto_activate_when_detected:true, created_time:"2023-12-21 20:16:06.674445", allow_detect_time:"2023-12-21 20:16:06.674445", is_timer_task_canceled:false, block_list:[], parent_list:[], lcl_period:1216543550, last_send_collect_info_period:0, block_callback_list_.count():1, ATOMIC_LOAD(&count_down_allow_detect_):0})
问题原因
在 OceanBase 数据库 V4.x 之前版本,死锁检测依赖于内部的“行锁”数据结构来维护行锁的 Holder 信息,当发生锁冲突时可以借由 Holder 信息来构建 WFG(wait-for-graph,等待关系图),但是 OceanBase 数据库 V4.0 版本的一个改动是去掉了“行锁数据结构”。因此 WFG(wait-for-graph,等待关系图)的构建要深入到多版本数据层面(MvccTransNode)去构建,并面对诸多正交场景。
TransNode 具有多版本,可能会被部分回滚,死锁检测需要进行适配。
提交/回滚:释放 mvcc trans node,等价于解行锁。
转储未提交:提前释放 mvcc trans node,但并不等价于解行锁。
fast commit:提前释放 mvcc trans node,但并不等价于解行锁。
提前解行锁(ELR):影响解开行锁的时机。
维护行锁(row key)到事务(txid)之间的映射关系由于和 OceanBase 数据库 V4.x 版本的其他功能正交,需要面临工程实现上的一系列复杂问题,在缺乏正确维护这个映射关系的前提下,没办法构建 WFG(wait-for-graph,等待关系图)检测死锁。
问题的风险及影响
业务发生死锁无法被检测到。
影响租户
影响 OceanBase 数据库中的 SYS 租户和 Oracle 租户以及 MySQL 租户。
影响版本
OceanBase 数据库企业版 V3.2.4 GA(oceanbase-3.2.4.0-100000072022102819)及之后版本、V4.1.0 GA(oceanbase-4.1.0.0-100001122023040322)之后版本、V4.2.1 GA(oceanbase-4.2.1.0-100000182023092722)及之后版本、V4.2.2 GA(oceanbase-4.2.2.0-100000082024011317)及之后版本。
解决方法
该问题没有办法解决,在修复前属于已知缺陷,但由于死锁检测整体属于“诊断功能”,因此并不会对 OceanBase 数据库的其他功能产生影响,但死锁检测本身的功能缺陷需要同步前线及客户,死锁检测具有基本检测能力,但并不能在所有场景下都正确工作。
规避方式
无法规避,只能等待修复。