分布式跨分区事务死锁,死锁检测日志只显示事务 ID,无法定位 SQL,业务随机写入超时,无明确锁等待报错

业务是分表分布式事务,单次事务更新 2 个不同分区的行;每日随机出现 10~50 笔写入超时,数据库无标准 deadlock 报错,仅 gv$transaction 中存在大量 STATE=ACTIVE、hold lock 事务;死锁视图gv$ob_deadlock为空,内核日志仅打印 tx_id,无原始 SQL 文本;普通行锁超时参数调整无效,死锁不会自动回滚。

1 个赞

你这个问题是OB 分布式两阶段提交(2PC)死锁,跨分区行锁形成等待环;本地死锁检测只能捕获单分区锁竞争,跨分区分布式死锁依赖全局死锁检测器,默认检测周期 60s,检测间隙内事务持续持有锁阻塞业务;且开启 SQL 审计才会持久化 tx_id 与 SQL 映射关系,未开审计无法溯源。

  1. 开启全局 SQL 审计持久化(在线生效,无需重启 observer):
    ALTER SYSTEM SET ob_sql_audit_permanent_enable = 1;
    ALTER SYSTEM SET ob_sql_audit_max_size = ‘100G’;
  2. 构建关联 SQL 查询,通过事务 ID 还原执行语句:
    SELECT t1.tx_id,t1.session_id,t2.sql_text,t1.state,t1.lock_wait_partition
    FROM gv$transaction t1
    LEFT JOIN gv$sql_audit t2 ON t1.session_id = t2.session_id
    WHERE t1.state = ‘ACTIVE’ AND t1.lock_wait_partition != ‘’;
  3. 调优分布式死锁检测频率,缩短等待自动回滚:
    ALTER SYSTEM SET ob_dist_deadlock_detect_interval = ‘5s’;
    ALTER SYSTEM SET ob_trx_idle_timeout = ‘30s’;
  4. 业务层根治方案:统一分布式事务更新分区访问顺序,固定先访问分区 A 再分区 B,打破锁等待环;大事务拆分为本地单分区小事务,规避 2PC 锁持有时间过长。
  5. 应急批量释放阻塞事务:
    SELECT CONCAT(‘KILL SESSION ‘’’,session_id,’’’’) FROM gv$transaction WHERE state=‘ACTIVE’ AND lock_wait_partition<>’’;
3 个赞

说的很详细,很不错

学到了,下次遇到问题,可以参考。