enq: tx - index contention等待超200秒并非锁本身慢,而是持有者无法释放锁的信号,根本原因包括lmon进程被io卡住、长事务未提交、索引键值高度集中、网络心跳延迟或私网丢包,导致grd更新停滞和锁链式等待。
oracle rac中global enqueue services(ges)本身不会直接导致应用挂起,但当ges资源争用严重、死锁未及时解除或关键进程(如lmon)被阻塞时,会引发级联等待,最终表现为应用长时间无响应——不是“卡住”,而是大量事务在enq: tx - contention、enq: tm - contention等事件上堆积,超时后连接断开、工单丢失。
为什么enq: TX - contention等待时间能到200秒以上?
这不是锁等待本身慢,而是持有者无法释放锁的信号。常见真实原因包括:
-
LMON进程被IO卡住(比如等待control file sequential read超70秒),导致整个GRD(Global Resource Directory)更新停滞,新锁请求全部排队 - 某个会话持锁后执行长事务(如未提交的大批量
INSERT),而其他实例频繁尝试修改同一行/索引块,形成“锁链式等待” - 索引键值高度集中(如自增ID+时间戳组合),多个实例并发插入导致同一索引分支块争用,触发
enq: TX - index contention - 网络心跳延迟或私网丢包,使LMD进程误判远端实例状态,反复重试跨实例锁协调,放大延迟
ORA-29770是症状,不是根因
看到Alert Log里ORA-29770: global enqueue process LMON (OSID xxx) is hung for more than 70 seconds,别急着重启实例。它只是LMHB进程的“最后通牒”,真正要查的是LMON当时在等什么:
- 立刻检查对应时间点的
ora1_lmhb_xxx.trc和ora1_lmon_xxx.trc,看Current Wait Stack第一行是什么事件 - 如果显示
gc current grant busy或DFS lock handle,说明GCS/GES内部消息通道已拥塞,需排查私网带宽和交换机buffer - 若显示
db file sequential read或control file sequential read,问题在存储层——控制文件或数据文件所在磁盘响应慢,不是数据库逻辑问题 -
latch: cache buffers chains高频出现,说明热点块争用已传导至GES层,得先定位SQL和对象(用Segments by Row Lock Waits视图)
RAC业务分割不当会放大GES压力
两个实例反复争抢同一张表的同一数据块,每次修改都要走完整GES流程:发消息→查GRD→协调Master→内存融合→回写。这个过程在高并发下极易成为瓶颈。实际规避方法很朴素:
- 按业务维度拆分写入路径:例如订单号末位奇偶分流到不同实例,让
INSERT天然避开相同索引块 - 避免全表扫描更新:RAC中
UPDATE /*+ FULL(t) */会触发大量TM锁广播,改用分区裁剪或主键精准更新 - 索引字段不要用纯单调值(如
SEQ.NEXTVAL):加盐(salt)或哈希打散,比如MOD(SEQ.NEXTVAL, 16)作为分区键一部分 - 确认
gv$lock里id1/id2值是否在不同实例间重复出现——重复即意味着资源master节点过载
GES问题从来不是孤立存在的。它像一面镜子,照出的是底层IO延迟、网络抖动、SQL设计缺陷或业务模型与RAC架构的错配。查AWR时盯着enq: TX等待时间没用,得顺着它往LMON trace、存储响应时间、私网丢包率三个方向同时挖。











