轉載ORA-01591錯誤故障處理

blueocean926發表於2009-01-13

ORA-01591錯誤故障處理

摘要

在訪問某些表的特定行時報ORA-01591錯誤

select * from BF_INCOME_EXPENSES_T

where account_id = 36816153

and user_id = 39964213

and city_code = '185'

ORA-01591: 鎖定已被有問題的分配事務處理72.0.1608712掛起

SQL> select count(*) from UNITELE.BI_MQSYNC_SOURCE_CONTROL_T1;

ORA-01591: 鎖定已被有問題的分配事務處理72.0.1608712掛起

由於該表是業務關鍵表,部分前臺業務受到影響。

關鍵詞:ORA-01591 DBA_2PC_PENDING 分散式事務

1.故障分析

首先,在遇到ORA錯誤時,我們不可能知道每個ORA錯誤都是什麼意思,所以透過oracle的聯機文件查錯誤的causeaction可以讓我們初步瞭解該錯誤。

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.

OracleORA-01591錯誤的描述是"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’該錯誤是由訪問一個處於prepared狀態的二階段事務所持有鎖的資源造成的。

下面簡單介紹一下分散式事務。

分散式事務,簡單來說,是指一個事務在本地和遠端執行,本地需要等待確認遠端的事務結束後,進行下一步本地的操作。如透過dblink update遠端資料庫的一行記錄,如果在執行過程中網路異常,或者其他事件導致本地資料庫無法得知遠端資料庫的執行情況,此時就會發生in doublt的報錯。此時需要dba介入,且需要分多種情況進行處理。

分散式事務的,會經歷3個階段:

1.PREPARE PHASE

1.1 決定哪個資料庫為commit point site。(注,引數檔案中commit_point_strength值高的那個資料庫為commit point site

1.2 全域性協調者(Global Coordinator)要求所有的點(除commit point site外)做好commit或者rollback的準備。此時,對分散式事務的表加鎖。

1.3 所有分散式事務的節點將它的scn告知全域性協調者。

1.4 全域性協調者取各個點的最大的scn作為分散式事務的scn

至此,所有的點都完成了準備工作,我們開始進入COMMIT PHASE階段,此時除commit point site點外所有點的事務均為in doubt狀態,直到COMMIT PHASE階段結束。

2.COMMIT PHASE
2.1 Global Coordinator
將最大scn傳到commit point site,要求其commit
2.2 commit point
嘗試commit或者rollback。分散式事務鎖釋放。
2.3 commit point
通知Global Coordinator已經commit
2.4 Global Coordinator
通知分散式事務的所有點進行commit

3.FORGET PHASE
3.1
參與的點通知commit point site他們已經完成commitcommit point site就能忘記(forget)這個事務。
3.2 commit point site
在遠端資料庫上清除分散式事務資訊。
3.3 commit point site
通知Global Coordinator可以清除本地的分散式事務資訊。
3.4 Global Coordinator
清除分散式事務資訊。

有關分散式事務的詳細資訊請參閱oracle聯機文件.

當前的分散式事務處於Two-Phase Commit機制中的prepared階段,這個階段事務已經在表上加鎖了,現在我們要訪問這些表,但事務沒有結束,一直持有鎖,導致訪問資源失敗報ORA-01591(在這裡需要指出:分散式事務所持有的鎖之所以堵塞讀操作,是因為oralce不知道該顯示哪個版本的資料) 如果結束這個事務,那相應的鎖也會釋放,這樣就能解決這個問題。我們知道要結束一個事務有兩種辦法:commitrollback。現在我們嘗試結束這個事務:

commit force '72.0.1608712';

ORA-02058: no prepared transaction found with ID 72.0.1608712

報錯並沒有發現prepared狀態的事務,由於該事務是分散式事務,我們首先想到的是dba_2pc_pending這個試圖

SQL> select * from dba_2pc_pending;

no rows selected

該試圖並沒有查到資訊,所以我們無法用commit force結束這個分散式事務,那麼現在我們檢視是否存在該事務,透過實際報錯,我們可以清晰的看到事務號為72.0.1608712,該事務在72號回滾段的0號事務槽上並且序列號是1608712這時查詢一個基表x$ktuxe,看看72號回滾段上是否有該事務。

SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */

2 KTUXESTA Status,

3 KTUXECFL Flags

4 FROM x$ktuxe

5 WHERE ktuxesta!='INACTIVE'

6 AND ktuxeusn= 72;

KTUXEUSN KTUXESLT KTUXESQN STATUS FLAGS

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

72 0 1608712 PREPARED SCO|COL|REV|DEAD

透過x$ktuxe這個基表,我們看到確實存在這個事務,而且是prepared狀態。

此時,我們基本清楚了這個問題的原因:當一個分散式事務死掉時,由於該事務沒有正常結束,導致事務持有的鎖一直沒有釋放,所以在訪問這個事務涉及的資源時,申請不到鎖資源,所以報ORA-01591。由於是分散式事務,當在dba_2pc_pending中查詢不到事務資訊時,我們是無法透過commit或者rollback結束該事務。

所以,我們目前的任務是模擬出這個分散式事務。由於dba_2pc_pending試圖是依賴於pending_trans$這個表,同時事務是與session關聯在一起的,所以我們需要手工往pending_trans$pending_sessions$兩個表中插入資料。

2.故障處理

SQL> alter system disable distributed recovery;

系統已更改。

SQL> insert into pending_trans$ (

2 LOCAL_TRAN_ID,

3 GLOBAL_TRAN_FMT,

4 GLOBAL_ORACLE_ID,

5 STATE,

6 STATUS,

7 SESSION_VECTOR,

8 RECO_VECTOR,

9 TYPE#,

10 FAIL_TIME,

11 RECO_TIME)

12 values( '72.0.1608712',

13 306206,

14 'XXXXXXX.12345.1.2.3',

15 'prepared','P',

16 hextoraw( '00000001' ),

17 hextoraw( '00000000' ),

18 0, sysdate, sysdate );

已建立 1 行。

SQL> insert into pending_sessions$

2 values( '72.0.1608712',

3 1, hextoraw('05004F003A1500000104'),

4 'C', 0, 30258592, '',

5 146

6 );

已建立 1 行。

SQL> commit;

提交完成。

SQL> alter system enable distributed recovery;

系統已更改。

此時,查詢dba_2pc_pending發現已有該事務,並且狀態是我們模擬出的prepared狀態

SQL> select * from dba_2pc_pending;

LOCAL_TRAN_ID GLOBAL_TRAN_ID STATE MIX A TRAN_COMMENTFAIL_TIME FORCE_TIME RETRY_TIME OS_USER

OS_TERMINAL HOST DB_USER

COMMIT#

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

72.0.1608712 XXXXXXX.12345.1.2.3 prepared no12-11-08 12-11-08

此時我們結束這個事務

SQL> COMMIT FORCE '72.0.1608712';

提交完成。

再次查詢dba_2pc_pending,發現事務是forced commit狀態,該事務已經結束。

SQL> select * from dba_2pc_pending;

LOCAL_TRAN_ID GLOBAL_TRAN_ID STATE MIX A TRAN_COMMENTFAIL_TIME FORCE_TIME RETRY_TIME OS_USER

OS_TERMINAL HOST DB_USER COMMIT#

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

72.0.1608712 XXXXXXX.12345.1.2.3 forced commit no12-11-08 12-11-08 12-11-08

透過x$kutxe 查詢事務資訊,發現事務釋放了回滾段,事務已經結束。

SQL> SELECT KTUXEUSN, KTUXESLT, KTUXESQN, /* Transaction ID */

2 KTUXESTA Status,

3 KTUXECFL Flags

4 FROM x$ktuxe

5 WHERE ktuxesta!='INACTIVE'

6 AND ktuxeusn= 72;

未選定行

此時,我們需要清除dba_2pc_pending中分散式事務的殘餘資訊

SQL> alter session set "_smu_debug_mode"=4; ――session級別設定回滾段處於手工管理模式,如果不設定這個引數,在回滾段自動管理模式下,清除事務資訊會報錯

會話已更改。

SQL> execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('72.0.1608712'); ――dbms包清除事務資訊

PL/SQL 過程已成功完成。

SQL> select * from dba_2pc_pending;

未選定行

測試訪問業務表

SQL> select count(*) from UNITELE.BI_MQSYNC_SOURCE_CONTROL_T1;

COUNT(*)

----------

367

問題解決。

其實,我在另外一個客戶處也碰到過類似問題,當時也是報ORA-01591,但是在dba_2pc_pending中可以查到prepared狀態的事務,此時只需要commit force結束這個事務,並清除事務資訊就可以了。對於上面的案例,我懷疑開發商直接清除了分散式事務資訊,但是事務並沒有結束,導致鎖資源得不到釋放報ORA-01591

總結:ORA-01591錯誤一般是由於分散式事務造成的,造成分散式事務失敗的原因主要是庫之間的網路突然中斷,造成兩個庫中的事務資訊不一致,所以會有殘餘的分散式事務資訊。此時,要針對不同的事務狀態做不同的處理。同時在遇到棘手的問題時,可以查詢metalink,該案例參考metalink文件:NOTE:

[@more@]

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

相關文章