首批通过分布式安全可靠测评,为关键业务系统打造
长事务和悬挂事务的巡检与应急方法
更新时间:2025-09-04 08:41
基本定义
长事务:事务的执行时间超过一定的阈值(业务定义),并且未执行 commit。
悬挂事务:事务已进入到提交阶段,并且事务的提交时间超过一定阈值。
巡检
长事务
在用户租户或者系统租户,优先使用用户租户下,可通过以下语句,查询所有长事务的事务参与者。
SELECT count(1)
FROM GV$OB_TRANSACTION_PARTICIPANTS
WHERE CTX_CREATE_TIME < date_sub(now(), INTERVAL 600 SECOND)
AND ROLE = 'LEADER'
AND ACTION = 'START';
上例中的 600s 表示默认的事务超时时间。
注意
事务巡检前需要确保系统中不存在无主的情况。
在用户租户或者系统租户,优先使用用户租户下,可通过以下语句,查询所有长事务的事务参与者。
SELECT count(1)
FROM GV$OB_TRANSACTION_PARTICIPANTS
WHERE CTX_CREATE_TIME < date_sub(now(), INTERVAL 600 SECOND)
AND STATE = 'INIT';
上例中的 600s 表示默认的事务超时时间。
注意
事务巡检前需要确保系统中不存在无主的情况。
在用户租户或者系统租户,优先使用用户租户下,可通过以下语句,查询所有长事务的事务参与者。
SELECT count(1)
FROM __all_virtual_trans_stat
WHERE part_trans_action<=2
AND ctx_create_time < date_sub(now(), INTERVAL 600 SECOND)
AND is_exiting != 1;
上例中的 600s 表示默认的事务超时时间。
悬挂事务
在用户租户或者系统租户,优先使用用户租户下,可通过以下语句,查询所有悬挂事务的事务参与者。
SELECT count(1)
FROM GV$OB_TRANSACTION_PARTICIPANTS
WHERE LAST_REQUEST_TIME < date_sub(now(), INTERVAL 600 SECOND)
AND ROLE = 'LEADER'
AND ACTION <> 'START';
上例中的 600s 表示默认的事务超时时间。
注意
事务巡检前需要确保系统中不存在无主的情况。
在用户租户或者系统租户,优先使用用户租户下,可通过以下语句,查询所有悬挂事务的事务参与者。
SELECT count(1)
FROM GV$OB_TRANSACTION_PARTICIPANTS
WHERE CTX_CREATE_TIME < date_sub(now(), INTERVAL 600 SECOND)
AND (STATE = 'PREPARE' OR STATE = 'REDO COMPLETE' OR STATE ='PRECOMMIT');
上例中的 600s 表示默认的事务超时时间。
注意
事务巡检前需要确保系统中不存在无主的情况。
在用户租户或者系统租户,优先使用用户租户下,可通过以下语句,查询所有悬挂事务的事务参与者。
SELECT count(1) FROM __all_virtual_trans_stat
WHERE part_trans_action > 2
AND ctx_create_time < date_sub(now(), INTERVAL 600 SECOND)
AND is_exiting != 1;
上例中的 600s 表示默认的事务超时时间。
应急方法
长事务
普通事务
捕获普通事务长事务。可以通过用户租户或者系统租户,优先使用用户租户查询视图
gv$ob_transaction_participants来捕获普通事务长事务。如果存在长事务,获取到该事务 ID(TX_ID)、scheduler 所在节点(SCHEDULER_ADDR)以及会话 ID(SESSION_ID)。通过 obclient 直连该事务 scheduler 所在节点上的用户租户或者系统租户,优先使用用户租户,通过
kill session来回滚该事务。
XA 事务
捕获 XA 事务长事务。可以通过用户租户或者系统租户,优先使用用户租户查询视图
gv$ob_transaction_participants来捕获 XA 事务长事务。如果存在 XA 事务长事务,获取到该 XA 事务 xid(FORMATID、GLOBALID、BRANCHID)。登陆到 XA 事务对应的用户租户下,使用
xa rollback匿名块来回滚事务。
捕获长事务。可以通过用户租户或者系统租户,优先使用用户租户查询视图
gv$ob_transaction_participants来捕获长事务。如果存在长事务,获取到该事务 trans id(TX_ID)、scheduler 所在节点(SCHEDULER_ADDR)以及会话 ID(SESSION_ID)。判断该事务是否为 XA 事务。在对应的用户租户(Oracle模式)下,使用 trans ID 作为筛选条件读取
gv$ob_global_transaction,存在记录即为 XA 事务。注意
XA 事务功能目前仅在 Oracle 租户下支持。因此,视图
GV$OB_GLOBAL_TRANSACTION仅可以在对应的 Oracle 租户下查询。如果该事务为 XA 事务,在对应的用户租户下,使用
xa rollback回滚事务;如果该事务为普通事务,则可以通过 obclient 直连该事务 scheduler 所在节点上的用户租户或者系统租户,优先使用用户租户 ,通过kill session来回滚该事务。
识别长事务。
SELECT * FROM __all_virtual_trans_stat WHERE part_trans_action<=2 AND ctx_create_time < date_sub(now(), INTERVAL 600 SECOND) AND is_exiting != 1;判断该事务是否服务于 XA 事务分支。
SELECT * FROM __all_virtual_global_transaction WHERE trans_id like '%6103238948955736893%';如果查询结果为空,则说明该事务为普通事务,可以执行第三步;否则,说明该内部事务服务于 XA 事务分支,可参考XA 事务基本运维 来终止该 XA 事务分支
根据上述长事务的 session_id,查询
__all_virtual_processlist,确定连接所在的 observer 机器,其中 svr_ip、svr_port 是 session 所在机器维护的本事务连接。select * from __all_virtual_processlist where id=3221487799;通过用户租户或者系统租户,优先使用用户租户,直连上述的 svr_ip,kill session。
kill 3221487799;
悬挂事务
普通事务
捕获悬挂事务。可以通过用户租户或者系统租户,优先使用用户租户查询视图
gv$ob_transaction_participants来捕获悬挂事务。对于普通事务的悬挂场景,需要进一步分析原因,再根据原因采用对应的应急手段。
XA 事务
捕获 XA 悬挂事务。可以通过用户租户或者系统租户,优先使用用户租户查询视图
gv$ob_transaction_participants来捕获 XA 悬挂事务。如果存在 XA 悬挂事务,获取到该 XA 事务的 xid(FORMATID、GLOBALID、BRANCHID)。登陆到 XA 事务对应的用户租户下,使用
xa rollback匿名块来回滚事务。
捕获悬挂事务。可以通过用户租户或者系统租户,优先使用用户租户查询视图
gv$ob_transaction_participants来捕获悬挂事务。如果存在悬挂事务,获取到该事务的 trans ID。判断该事务是否为 XA 事务。在对应的用户租户(Oracle模式)下,使用 trans ID 作为筛选条件读取
gv$ob_global_transaction,存在记录即为 XA 事务。注意
XA 事务功能目前仅在 Oracle 租户下支持。因此,视图
GV$OB_GLOBAL_TRANSACTION仅可以在对应的 Oracle 租户下查询。如果该事务为 XA 事务,在对应的用户租户下,使用
xa rollback回滚事务;如果是普通事务,则需要进一步分析悬挂原因(可能的原因包括日志流无主、磁盘爆等)。
leader 上事务无法结束
需要确认是否有无主,内存爆等问题,需要解决掉异常,悬挂事务才能解决掉;如果不能确定,可以联系技术支持人员协助解决。
查询事务涉及的所有表是否存在无主,首先确认事务涉及的所有 partition。
SELECT svr_ip, trans_id, participants FROM __all_virtual_trans_stat WHERE part_trans_action > 2 AND ctx_create_time < date_sub(now(), INTERVAL 600 SECOND) AND is_exiting != 1;根据查询结果,participants 就是该事务锁涉及的所有表信息。
对 participants 里面的每个 pkey,分别确认上述分区列表是否有主:(记住,每个 pkey 都要 check)
select svr_ip, svr_port, table_id, partition_idx, role, status, replica_type from __all_virtual_clog_stat where table_id=1099511677777;上述查询结果,重点关注 role 这一列,如果全是 FOLLOWER,则表示无主;否则进行第三步。
确认该租户是否存在内存爆:
select * from __all_virtual_tenant_memstore_info where tenant_id=1001;确认
total_memstore_used的量是否已经到了 memstore_limit,或者其他内存异常的信息。
如果第二步、第三步任何一种情况出现,请联系技术支持协助排查问题。
备机日志回放慢,导致事务状态未推进完成
如果是这种情况,需要确认备机租户内存、网络带宽相关是否跟 Leader 异构。如果评估确实可能出现落后,紧急情况下,可以通过如下操作来尝试恢复:
确认上述异常事务只在备机存在。
查询报警事务所对应的 svr_ip、
partition具体信息。SELECT svr_ip, svr_port, trans_id, `partition` FROM __all_virtual_trans_stat WHERE part_trans_action > 2 AND ctx_create_time < date_sub(now(), INTERVAL 600 SECOND) AND is_exiting != 1;根据上述查询到的
partition中记录的 table_id 信息,确认当前 pkey 对应的 leader 位置。select svr_ip, svr_port from __all_virtual_clog_stat where role='LEADER' and table_id = xxx;如果第一步和第二步对应的 svr_ip 不同,说明异常事务在 follower 上存在。
查询上述事务对应的分区,目前集群中的记录条数:
select count(1) from __all_virtual_trans_stat where trans_id like '%{选取第一步 trans_id 中的hash 字段}%' and `partition` like '%xxx%';如果上述查询结果为 1 条,说明只有备机上存在,可以按照预案来执行。
保留进程现场。
obstack pid > /tmp/pstack.log杀掉进程。
kill -9 {pid}; // pid 为 observer 进程的 id重新拉起进程。
在 admin 用户下
cd /home/admin/oceanbase ./bin/observer
适用版本
OceanBase 数据库 V2.x、V3.x、V4.x 版本。