你以为只是慢查询?其实是DBLink在悄悄“锁死”你的数据库!
某医院核心系统于上午10:00左右突发故障,现象表现为客户端应用连接数据库服务器时出现严重卡顿甚至完全卡死。运维人员介入后,为尽快恢复业务,对数据库实例进行了紧急重启。重启后,业务暂时恢复正常。
在对数据库告警日志(alert.log)进行例行检查时,我们发现了一条关键的错误信息:ORA-24756: transaction does not exist。这条报错为后续的深入排查提供了重要线索。
初步排查:关联MOS文档
根据经验,ORA-24756 错误通常与分布式事务或数据库链接(DBLink)有关。我们立即查询了My Oracle Support (MOS) 文档,并关联到了一个已知的Bug。
MOS文档描述 (Bug:24406027)
If multiple database links were used from one database to another, and if one of them had a connection failure or similar error, then in some cases after commit, RECO would loop reporting ORA-24756.
简译:当在两个数据库之间使用多个DBLink时,如果其中一个连接失败,在某些情况下,提交操作后恢复进程(RECO)会循环报告
ORA-24756错误。
该Bug的描述与我们的场景高度相关,尤其是其中提到的临时解决方案——“The only workaround was to restart the instance.”(唯一的规避方法是重启实例),这与我们现场的应急处理方式完全吻合。这让我们初步判断,故障很可能由DBLink的不稳定或异常导致。
深入诊断:定位Hang的根源
尽管重启暂时解决了问题,但根本原因尚未查明,风险依然存在。当日晚些时候,现场工程师反馈在查询某个视图时再次出现Hang住的现象,这为我们提供了精准的排查入口。
定位Hang住的SQL
现场工程师反馈,执行以下SQL时客户端无响应:
图1:通过DBLink查询视图的SQL语句被挂起
该SQL select * from v_his_mrhp@EMR_OPERATION_LINK 明确使用了DBLink(@EMR_OPERATION_LINK),这进一步印证了我们对DBLink的怀疑。
分析等待事件
为定位数据库内部的瓶颈,我们立即查询了会话等待事件视图 v$session_wait。通过以下查询,我们过滤掉了常规的空闲等待,聚焦于异常等待事件。
select event, p1, p2, sid from v$session_waitwhere event not like 'SQL%' and event not like 'rdbms%';
图2:大量会话处于 "cursor: pin S wait on X" 等待事件
查询结果(如图2所示)非常典型:大量的会话都阻塞在 cursor: pin S wait on X 等待事件上。这个等待事件意味着多个会话正在以共享模式(S)请求一个游标(cursor)的pin,但该游标已被另一个会话以排他模式(X)持有。通俗地说,就是发生了严重的库缓存(Library Cache)争用,通常由SQL硬解析、编译或对象依赖问题引起。
追溯视图定义
结合Hang住的SQL和等待事件,我们判断问题出在 v_his_mrhp 这个视图的定义上。我们找到了该视图的创建语句,发现其结构复杂,并且通过DBLink(@HISXIN)调用了另一个数据库中的对象。
图3:涉及跨库调用的复杂视图定义
至此,一条调用链逐渐清晰:客户端查询数据库A的视图,该视图通过DBLink查询数据库B的对象。为了彻底查清问题,我们联系了数据库B的管理员,请求查看被调用视图的定义。
根因定位与最终解决方案
在查看数据库B的视图创建语句时,我们发现了问题的症结所在:数据库B的视图反过来又通过DBLink调用了数据库A的视图!
这就形成了一个致命的循环调用:
步骤1: 用户在数据库A上查询视图 V_A。步骤2: 视图 V_A的定义中包含对数据库B视图V_B的查询(通过DBLink)。步骤3: Oracle在解析 V_A时,需要通过DBLink连接到数据库B,并解析V_B。步骤4: 在解析数据库B的视图 V_B时,发现其定义中又包含了对数据库A视图V_A的查询(通过另一个DBLink)。步骤5: 数据库B尝试连接回数据库A解析 V_A,从而形成了一个无法终止的递归调用循环。
这个循环导致SQL解析过程无限递归,占用了库缓存中的对象并持有排他锁(X lock),其他所有尝试访问该对象的会话都只能等待(S wait),最终表现为大量的 cursor: pin S wait on X 等待事件,使整个数据库陷入“假死”状态。
处理方法
与数据库B侧的业务开发人员沟通,明确其调用场景和真实需求。最终,协助其修改了数据库B的视图定义,去掉了对数据库A的反向DBLink调用,改为在本地获取所需数据。
修改完成后,问题得到彻底解决,数据库恢复稳定运行。
总结与反思
本次故障排查是一次典型的从现象到本质的诊断过程。作为Oracle运维专家,我们可以从中总结出以下几点经验:
警惕特定错误码: ORA-24756是一个强烈的信号,直接将排查方向指向了分布式事务和DBLink。善用等待事件分析: cursor: pin S wait on X是诊断数据库Hang问题的利器,它能快速定位到库缓存争用的根源。代码审查的重要性: 跨库调用的设计必须经过严格审查。应极力避免DBLink的循环依赖,这种设计缺陷在开发阶段很难被发现,但在生产环境中可能引发灾难性后果。 跨团队协作是关键: 复杂的系统问题往往涉及多个技术栈和团队。在本案例中,若没有与对端数据库管理员和开发人员的有效沟通,将无法定位到循环调用的根本原因。