由JTA分布式事务Timeout值引发的锁定及解决

来源:互联网 发布:电脑程序员工资多少 编辑:程序博客网 时间:2024/06/19 01:14

声明:本文思路解决受dbsnake老师指点,特此感谢!

 

分布式系统较传统的单点系统,具有较强的可拓展性和可用性,是目前大型应用系统普遍采用的设计模式。但是较传统系统,分布式系统无论从复杂性还是出现故障的机率看,都是远远超过单点系统。当我们选择开发分布式系统的时候,就意味要倾注更多的精力。

 

1分布式事务

 

分布式事务是分布式系统的一个重要研究范畴。在Oracle中,采用“二阶段提交”(Two phases submit)作为分布式事务的处理模型。简单的说,当一个事务涉及操作对象分布在不同的数据库上。传统的锁机制和事务模型都是建立在单实例数据库基础上的。分布式事务要保证各个节点上事务都成功的前提下,才能确定事务提交完成。只要有一个事务没有完成,所有节点的事务都要进行rollback

 

分布式事务一个最难处理的问题,就是通信带来的timeout取值。分布式事务要伴随着大量的节点间通信交互,确定其他工作节点是否事务是否完成。这种等待是很大的问题,因为节点不知道其他节点不响应是“因为节点已经死亡,还是节点网络繁忙”。所以timeout设置就是一个很大的问题。

 

这种问题的极端体现就是,一个事务中涉及到多个节点内容。当一个节点锁住一些对象,开启了事务过程,就不断地等待其他节点的响应。而由于各种原因,没有相应到来。这样就需要进行事务回收问题。

 

通常情况下,Oracle是可以自动处理这种问题的。在一个分布式事务中,有三个层面的timeout参数解决分布式事务锁。

 

ü       全局事务timeoutGlobal Transaction Timeout):在这种方式下,Oracle是不负责分布式事务管理的。Oracle将事务管理权交付给应用处理,如JTA事务容器。这种方式的事务管理,完全取决于应用程序配置内容。比如在JDBCJTA中,有专门的Time out参数;

ü       Session Timeout:指定了一个事务可以持续的最长时间,超过了这个时间就会被自动回收中断。一个XA事务与Oracle Process的关系是比较松散,可以进行detach操作。当一个分布式事务失败的时候,Oracle可以通过时间设置情况,将XA事务detach from the process

ü       Oracle内部的distributed_lock_timeout限制住一个分布式事务可以锁住对象的最长时间。该参数通常默认设置一个很大的取值;

 

上述的三个timeout中,大小配置顺序通常是:global transaction timeout < session timeout < distributed_lock_timeout

 

很多时候,配置过大的timeout值,可能会引起一些问题和对象锁定

 

2、“shadow session”现象

 

当我们使用JTA事务模型的时候,分布式事务管理权是从Oracle转移到JTA框架来进行管理。但如果事务中出现JTA的异常终止,就可能出现分布式问题。检查系统中,存在事务信息。

 

--篇幅原因,结果列有删减;

SQL> select * from v$transaction;

 

ADDR                XIDUSN   XIDSLOT    XIDSQN    UBAFIL    

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

070000007B5AC368         1         6     42735         3   

 

 

存在事务,该事务的标识是(1642735)。此时存在被锁定的对象。

 

 

SQL> select * from v$locked_object;

 

   XIDUSN   XIDSLOT    XIDSQN OBJECT_ID SESSION_ID ORACLE_USERNAME OS_USER_NAME      LOCKED_MODE

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

        1         6     42735    114245       181SYSMAN      3

 

 

v$lock_object中,可以看到当前事务锁定object_id=114245的对象,会话编号为sid=181,锁模式为共享锁模式。注意:此时user显示的是sysman的系统内置用户。

 

此时对象是存在的,也能确定锁对象确实存在。

 

 

SQL> select * from dba_objects where object_id=114245;

 

OWNER                         OBJECT_NAME 

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

NBS_COMMON                    BAT_LOCK    

 

 

SQL> select * from bat_lock for update nowait;

select * from bat_lock for update nowait

 

ORA-00054:资源正忙,但指定以NOWAIT方式获取资源,或者超时失效

 

 

下面进行sid=181检查,发现该会话是不存在v$session中的。也找不到对应的共享锁信息。

 

 

SQL> select count(*) from v$session where sid=181;

 

 COUNT(*)

----------

        0

 

SQL> select * from v$lock where id1=114245;

 

ADDR            KADDR                  SID TYPE     

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

 

 

最为诡异的情况是v$locked_object中,oracle_username不断的幻象读。

 

 

SQL> select * from v$locked_object;

 

   XIDUSN   XIDSLOT    XIDSQN OBJECT_ID SESSION_ID ORACLE_USERNAME              

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

        8        12     48826    114245       181                               

 

SQL> select * from v$locked_object;

 

   XIDUSN   XIDSLOT    XIDSQN OBJECT_ID SESSION_ID ORACLE_USERNAME              

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

        8        12     48826    114245       181   NBS                           

 

 

 

没有v$session信息就无法进行session级别的kill操作。同时,使用OS级别的Server Process kill操作也没有作用。Oracle始终不能对事务资源进行回收。

 

3、分析问题和解决

 

该现象产生的原因是JTA事务的timeout值设置过大造成的。在使用JTA事务模型中,存在一个事务timeout参数,默认值为5分钟。如果使用JTA进行分布式事务,Oracle会将分布式事务的控制权交出,由JTA进行事务控制。

 

这就是我们在第一部分中说的Global Transaction Timeout取值。JTA Timeout变相定义了在使用JTA中,一个数据库操作事务可以持续多长时间。如果超过这个时间,JTA会自动中断正在执行的事务,并且进行回滚。这也就限制了一个事务的时间长短。

 

OLTP系统来说,我们一般期望事务规模尽可能小且短,时间越快越好。从而保证并发性和可拓展性。对OLAP系统来说,就有所差别。一些SQL执行过程可能会较长。所以对不同系统设置不同的JTA Timeout值,是必要的。

 

JTA是会向Oracle抢夺事务控制权的。如果JTA在一个分布式事务进行中崩溃,那么Oracle是不会对事务进行资源回收和锁释放的。

 

在我们的例子中,就是一个明显的表现。Oracle只有经过JTA Timeout设置的时间,才可能会进行回收。

 

那么,有没有办法在JTA失败后,不经过Timeout时间进行回收呢?在MOS 1248848.1中,我们找到了Java代码XA_rb.java,执行这个类方法,就可以实现资源的回收。代码地址:http://space.itpub.net/17203031/viewspace-709216

 

该程序的原理,就是使用Oracle JDBC实现中的类,对特定事务进行强制回收。作为参数,要输入连接数据库的URL地址,以及回收事务的标识。

 

 

++ URL:jdbc:oracle:thin:@10.1.15.64:1521:NBSDEV

++ Rollback of Local_tran_ID     :1.6.42735

++  got  XA resource  handle

++  got  Connection  handle

++ SQL : select     g.K2GTIFMT,      g.K2GTITID_EXT,      g.K2GTIBID, rawtohex( g.K2GTITID_EXT), rawtohex(g.K2GTIBID)from sys.v_x$k2gte      g,  sys.v_x$ktcxb t, sys.v_x$ktuxe x     where   g.K2GTDXCB      =t.KTCXBXBA      and x.KTUXEUSN = t.KXIDUSN(+) and x.KTUXESLT = t.KXIDSLT(+) and x.KTUXESQN =t.KXIDSQN(+)  and t.KXIDUSN=1 and t.kXIDSLT=6 and t.kXIDSQN= 42735

++ Getting XID for Local_Tran_ID:  1.6.42735

+ Found global   XID: -->

++  Format Id:  1096044365

++   Group Id:  31302E312E362E3233392E746D30303030313031303435

++  Branch Id:  31302E312E362E3233392E746D31

 

 -> Would     your really     like to     continue (yes or no):

yes

...   doing Rollback

...   Rollback done !

 

 

此时,再进行检查,可以发现事务被回收。

 

 

SQL> select * from v$locked_object;

 

   XIDUSN   XIDSLOT    XIDSQN OBJECT_ID SESSION_ID ORACLE_USERNAME   

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

 

SQL> select * from bat_lock for update nowait;

 

LOCK_NAME

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

TASK_ACCESS

 

SQL> rollback;

Rollback complete

 

 

 

4、结论

 

分布式事务较之传统事务模型,复杂性和管理难度要远远大于传统事务。Oracle内部支持分布式事务,有二阶段提交模型。一些事务管理框架,也都存在相应的事务模型方法。

 

对分布式事务中存在的问题,需要重点关注。

原创粉丝点击