ORACLE懸疑分散式事務問題處理

資料和雲發表於2020-03-23




摘要:本文介紹遇到ORACLE懸疑分散式事務報錯問題的處理過程

當需要在多個Oracle資料庫之間進行資料一致性操作時,就會用到分散式事務。
例如:

insert into T_log@remote_db;  --遠端資料庫插入
insert into T_local;          --本地資料庫插入
commit;

分佈在本地和遠端兩個db的事務同時操作,這就構成了一個分散式事務。

分散式事務採用Two-Phase Commit提交機制,保證分佈在各個節點的子事務能夠全部提交或全部回滾的原子性。在這種機制下,事務處理過程分為三個階段:

  1. PREPARE:發起分散式事務的節點通知各個關聯節點準備提交或回滾。各關聯節點此時會做三個事情:重新整理redo資訊到redo log中;將持有的鎖轉換為懸疑事務鎖;取各節點中最大的SCN號進行同步
  2. COMMIT:寫入commited SCN,釋放鎖資源
  3. FORGET:懸疑事務表和關聯的資料庫檢視資訊清理

由於分散式事務涉及到多個資料庫之間進行操作,偶爾會遇到一些異常情況(例如系統或網路中斷)導致上述三個階段出現異常,這就在一個或多個節點上,產生不完整的“懸疑分散式事務”。
大多數情況下,出現這種問題,Oracle會由Reco程式進行自動修復,Oracle資料庫會在dba_2pc_pending 和dba_2pc_neighbors等多個檢視中記錄分散式事務相關的資訊,事實上reco程式也是基於這些資訊去做自動修復的。
Reco程式會嘗試連線到其他節點獲取分散式事務資訊,然後嘗試修復失敗的事務,並將對應的事務中的記錄刪除。
但有些情況下(例如節點無法正常訪問或事務表中記錄的資料不完整),Reco程式不能正常完成這個工作,就會丟擲異常。對於分散式事務,對應的異常程式碼區間是ORA-02040 - ORA-02099,可透過alert日誌檢視到錯誤資訊。
例如:

ORA-02054: transaction in-doubt
The transaction is neither committed or rolled back locally, and we have lost communication with the global coordinator.

此時往往需要手工處理進行干預。

以下是三種常見的分散式事務問題場景:

  1. dba_2pc檢視中有資料,但分散式事務已經不存在
  2. 分散式事務存在,但dba_2pc檢視中沒有資料
  3. 事務和檢視資料都有,但是執行commit force或rollback force時hang住

透過報錯會有提示,例如:

ORA-01591: lock held by in-doubt distributed transaction 10.20.360
這個10.20.360就是我們需要檢查分散式事務ID

場景一:dba_2pc檢視中有資料,但分散式事務已經不存在
檢視有資料,那麼先檢查資料的狀態

select * from dba_2pc_pending where local_tran_id='10.20.360';

主要看state欄位。
如果事務已經是committed, rollback forced或者commit forced狀態,表示事務已經完成了,但是在FORGET階段處理時,資料庫字典的資訊沒能及時清除。此時,我們呼叫oracle的清理丟失事務資訊的語句就可以完成處理:

execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY ('10.20.360');

如果事務是PREPARED狀態,但是在事務表中又沒有活動的事務:

SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */
KTUXESTA Status,
KTUXECFL Flags
FROM x$ktuxe
WHERE ktuxesta!='INACTIVE'
AND ktuxeusn= 10;   --注意替換這裡的回滾段號(xid=usn.slot.(sqn+1))
----沒有活動的事務

那此時需要手工清理丟失事務的資訊

set transaction use rollback segment SYSTEM;
delete from sys.pending_trans$ where local_tran_id = ;
delete from sys.pending_sessions$ where local_tran_id = ;
delete from sys.pending_sub_sessions$ where local_tran_id = ;
commit;

場景二:分散式事務存在,但dba_2pc檢視中沒有資料

遇到ORA-2054, ORA-1591等錯誤,檢查dba_2pc檢視沒有記錄,這種場景不常見,只在少數極端的情況下出現。
先確認現象,分別檢查x$ktuxe和 dba_2pc_pending檢視,查詢語句與場景一相同
在這種情況下無論是執行commit force還是rollback force,都會直接丟擲異常:

 commit force '10.20.360';
 ORA-02058: no prepared transaction found with ID 10.20.360

這時我們需要將檢視對應的基表資料補入,然後再執行rollback force。

  alter system disable distributed recovery;
  insert into pending_trans$ (
    LOCAL_TRAN_ID, GLOBAL_TRAN_FMT,
    GLOBAL_ORACLE_ID,STATE, STATUS,
    SESSION_VECTOR,RECO_VECTOR,TYPE#, FAIL_TIME, RECO_TIME)
    values( '10.20.360', /* <== Replace this with your local tran id */
    306206, 'xxxxxxxx.00000.0.0.0', 
    'prepared','P', 
    hextoraw( '00000001' ),hextoraw( '00000000' ), 0, sysdate, sysdate );
  insert into pending_sessions$ 
    values( '10.20.360',1, hextoraw('00000000'), 'C', 0, 1433927502, '', 14);
    --1433927502為DBID, 14為userid
  commit;
  rollback force '10.20.360';
  EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('10.20.360'); 
  --手工清理事務資訊

場景三:事務和檢視資料都有,但是執行commit force或rollback force時hang住

如果檢視和事務表中都有資料,而且狀態是PREPARED,先執行commit force或rollback force,通常就能解決問題,但有時候也會遇到執行force處理時hang住
嘗試purge事務資訊時,有提示報錯:

BEGIN DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('10.20.360'); END; 
* 
ERROR at line 1: 
ORA-06510: PL/SQL: unhandled user-defined exception 
ORA-06512: at "SYS.DBMS_TRANSACTION", line 94 
ORA-06512: at line 1

此時需要進行場景一和場景二的結合起來的所有步驟:

1. 先將檢視對應的基表資料刪除
   delete from sys.pending_trans$ where local_tran_id = '10.20.360'; 
   delete from sys.pending_sessions$ where local_tran_id = '10.20.360'; 
   delete from sys.pending_sub_sessions$ where local_tran_id ='10.20.360'; 
   commit;
2. 再插入pending_trans$和pending_sessions$資料,見場景二
3. rollback force '10.20.360'; 
4. Purge the transaction: 
   exec dbms_transaction.purge_lost_db_entry('10.20.360');


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556440/viewspace-2682006/,如需轉載,請註明出處,否則將追究法律責任。

相關文章