在 Oracle RAC 环境中,锁冲突主要可以分为两类:一类是应用层的事务级锁冲突,典型等待事件如 enq: TX;另一类是底层缓存融合(Cache Fusion)机制带来的全局缓存争用,常见表现如 gc current block busy、gc buffer busy acquire 等。两者的成因和排查路径差别较大,下面分别梳理。
一、应用层事务级锁冲突:enq: TX
这类冲突本质上多数来自业务 SQL 设计问题,但在 RAC 多节点并发访问下,阻塞效应会被进一步放大。
1. 常见场景
- 主键或唯一键争用:多个会话同时插入或更新带有相同唯一约束的记录。
- 位图索引更新:多个会话并发更新同一个位图索引段,很容易触发严重的
TX 锁等待。
- 无索引外键删除:删除父表记录时,如果子表外键列缺少索引,子表可能被加上表级锁,或者出现明显的行级争用。
- 长事务:事务执行时间过长,行锁被长时间持有,后续需要访问相同行的会话只能等待。
2. 排查方法
- 使用 ASH 定位:查询
gv$active_session_history,过滤 event = 'enq: TX',再结合 sql_id、blocking_session 和 blocking_inst_id,可以快速定位到引发冲突的具体 SQL 和阻塞源节点。
- 应用层优化:缩短事务生命周期,操作完成后及时
COMMIT;优化业务逻辑,避免对同一行或相邻行进行高频并发更新。
二、缓存融合争用:Global Cache Wait Events
这类冲突源于 RAC 底层的数据块跨实例传输与一致性维护,通常表现为 gc current block busy、gc buffer busy acquire 等等待事件。
1. 常见场景
- 热点块争用(Hot Block):多个实例高频访问或修改同一个数据块,典型场景包括序列生成的主键索引根块、全局计数器表的并发更新、小表的全表扫描等。
- 跨实例 DML 冲突:多个实例同时更新同一行或相邻行,导致数据块在实例间频繁传递,也就是常说的 Ping-Pong 效应。
- 网络与硬件瓶颈:私有互联网络延迟过高、带宽不足,或者存储响应较慢,都会拖慢数据块传输,进而放大全局缓存等待。
2. 排查方法
- 定位热点对象:通过
gv$session_wait 或 gv$active_session_history 获取等待事件的 P1(文件号)和 P2(块号),然后关联 dba_extents 视图,精确找到发生争用的表、索引或分区。
- 检查网络与进程:使用
ping 或 ipref 等工具测试私网延迟;同时检查 LMS(全局缓存服务进程)是否存在 CPU 瓶颈或繁忙状态。
- 架构与参数优化:
- 应用隔离与分区:使用表分区(Partitioning)将热点数据分散到不同的物理段,或者使用服务绑定(Service Affinity)把相关事务固定到特定节点,降低跨实例争用。
- 序列与索引优化:为序列设置较大的
CACHE 值,例如 1000,避免序列生成成为全局争用点;对于单调递增的索引列,可以考虑使用反向键索引(Reverse Key Index)。
- 减少大表全表扫描:优化 SQL,避免在 RAC 环境中进行跨实例的大表全表扫描,防止大量数据块挤占全局缓存。
实际排查时,这类问题通常还要结合 AWR 和告警日志进一步收敛范围,云栈社区上也有不少类似的 RAC 锁冲突案例可以参考。
|