texedo 分布式事务

时间:2023-03-10 05:38:26
texedo 分布式事务

1、问题现象

但是实际情况,完全出乎笔者的想法。检查一般对象数据表锁定,只需要检查v$locked_object和v$transaction视图,就可以定位到具体人。但是检查之后的结果如下:

SQL> select * from v$locked_object;

XIDUSN XIDSLOT XIDSQN OBJECT_ID SESSION_ID

---------- ---------- ---------- ---------- ----------

SQL> select * from v$transaction;

ADDR XIDUSN XIDSLOT XIDSQN

---------------- ---------- ---------- ----------

两个关键视图中,没有锁定的对象,也没有正在进行没有提交的事务。那是不是没有锁定呢?尝试对数据表加锁。

SQL> select * from nbs_common.inc_inputlog for update;

select * from nbs_common.inc_inputlog for update

ORA-01591:锁被未决分布式事务处理4.30.31555持有

SQL> select count(*) from nbs_common.inc_inputlog;

COUNT(*)

----------

426

系统没有像一般阻塞那样等待,而是报错Ora-01591。并且提示锁被一个分布式事务持有,不能实现加锁操作。

看来是一个没有见到过的新错误。

2、分析问题

Ora-01591错误究竟是什么呢?我们使用oerr工具查看该错误编号,看看有没有值得关注的信息。

[oracle@bspdev ~]$ oerr ora 01591

01591, 00000, "lock held by in-doubt distributed transaction %s"

// *Cause: Trying to access resource that is locked by a dead two-phase commit

// transaction that is in prepared state.

// *Action: DBA should query the pending_trans$ and related tables, and attempt

// to repair network connection(s) to coordinator and commit point.

// If timely repair is not possible, DBA should contact DBA at commit

// point if known or end user for correct outcome, or use heuristic

// default if given to issue a heuristic commit or abort command to

// finalize the local portion of the distributed transaction.

简单的说,01591错误的原因是该对象被一个处在“in-doubt”状态的分布式事务锁定。分布式事务使用的是“two-phase commit”二阶段提交技术。解决该问题的方法就是查看内部表pending_trans$,确定分布式事务信息。这种状态的事务主要是由于在进行分布式事务时候,发生网络突发中断的情况,引起分布式事务无法正常结束,等待中断节点的事务响应。于是,各节点的事务所锁定的表就不会被释放掉。

此时,我们检查视图DBA_2PC_PENDING(或者基表pending_trans$),查看是否存在这种情况。

SQL> select * from DBA_2PC_PENDING;

LOCAL_TRAN_ID GLOBAL_TRAN_ID STATE

---------------------- ----------------------------------------------------- ----------------

4.30.31555 096044365.31302E312E33392E38392E746D30303034313030303237 Pepared

(篇幅原因,有省略……)

果然,当前存在一个阻塞分布式事务,处在prepared状态。

3、知识介绍

现代数据库系统往往伴随着复杂的结构和环境,其中分布式数据库组成是一个重要方面。系统后台的数据库系统不再是由单个数据构成,而是由多*立数据库、甚至是多台异构数据库构成。这种情况下,分布式事务就是开发设计人员不能不面对的一个难题。

处理分布式事务的方案,有两种趋势。其一是借助数据库自身的分布式处理能力,如Oracle的分布式二阶段提交模型,进行多个数据库的分布式事务同步。其二是将分布式事务处理权交付给应用中间层,让应用去处理分布式事务问题。

进行分布式事务的时候,使用的“二阶段提交”模型,大致分为几个过程。(参考:http://blog.itpub.net/post/38439/477038

ü Prepare阶段:多个数据库的commit_point_strength进行比较,确定出一个数据库作为commit point site。由全局协调者(Global Coordinator)通知除了commit point site外所有节点准备好commit和rollback。同时,各节点对事务相关数据表加锁。之后,各个节点通知全局协调者自己的SCN,选择最大的那个SCN作为当前事务的SCN;注意,从此刻开始,除了commit point site外,其他节点均进入in_double状态;

ü Commit阶段:全局协调者将确定好的最大SCN通知给commit point site,授权该节点进行commit操作。Commit point site进行事务commit/rollback之后,通知全局协调者事务完成。全局协调者通知其他所有节点进行commit操作;

ü Forget阶段:当各个节点结束事务之后,通知commit point site当前事务已经完成。当全部都完成了,commit point site开始清理分布式事务信息,然后通知全局协调者清理信息。最后全局协调者将最后清理掉本地的事务信息;

当前问题,主要是源于在进入prepared阶段之后,发生了网络中断的现象,引起commit的阶段不能等待到事务信息。所以,才会一直处在Prepared状态,数据表也就不会进行释放。

4、问题解决

对于这个事务,只能通过连接网络或者强制提交回退事务来结束。我们可以使用commit force或者rollback force来进行处理。

SQL> rollback force '4.30.31555';

Rollback complete

Rollback force参数是DBA_2PC_PENDING中记录本地事务信息的编号。

此时,再次查看数据。

SQL> select * from DBA_2PC_PENDING;

LOCAL_TRAN_ID GLOBAL_TRAN_ID STATE

---------------------- ----------------------------------------------------------

4.30.31555 096044365.31302E312E33392E38392E746D30303034313030303237forced rollback

此时,该事务状态已经变化为forced rollback。已经强制回退。

SQL> select seq_number from nbs_common.inc_inputlog where rownum<2 for update;

SEQ_NUMBER

--------------

2

5、结论

这个故障解决,使我获取到如下认识:

ü 系统一旦涉及到分布式数据库,整体的复杂性就要提升很多。所以,要对分布式事务处理技术有非常成熟的认识和理解,而且要经过严格的测试;

ü 锁表的现象多种,不同事务类型,查看信息的方式有所差异;