由JTA分散式事務Timeout值引發的鎖定及解決

realkid4發表於2011-10-25

 

宣告:本文思路解決受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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章