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

 

声明:本文思路解决受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        181 SYSMAN       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: --&gt

++   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内部支持分布式事务,有二阶段提交模型。一些事务管理框架,也都存在相应的事务模型方法。

 

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

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-709661/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/17203031/viewspace-709661/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值