Programming/Oracle

ORA-01591:lock held by in-doubt distributed transaction에러

초록깨비 2024. 9. 13. 14:39
728x90

 

ORA-01591 : distributed transaction 에러

                      분산 트랜잭션의경우 2PC(2 Phase commit) 수행 중 Fail이 발생하면

                      관여된 일부 DB에서는 rollback or commit되고

                      일부는 distributed lock이 걸린 상태로 지속 될 수 있다.

                     

                     이런 pending 된 transaction은 RECO가 자동으로 정리해 주나 정리가 안되면

                     ORA-01591에러가 발생하므로 Pending transaction을 정리해야 한다

 

 

1)  DBA_2PC_PENDING을 조회

     sqlplus system/manager

 

     SQL> select local_tran_id, global_tran_id, state, mixed, host, commit#

                from dba_2pc_pending ;

 

     조회 후 여러 row가 나오면 ora-01591에러에 나오는 local_transaction_id 값과

     조회 결과의 local_tran_id값을 비교하여 일치하는 row를 확인한다 

     이때 local_tran_id 와 global_tran_id의 뒷부분 숫자가 동일하면

            이 node가 global coordinator임을 의미한다

 

    이런 경우

       sqlplus system/manager

  

       SQL > select local_id, in_out, database, dbuser_owner, interface

                   from dba_2pc_neighbors ;

     

               => 여기 나오는 row들이 분산 트랜잭션에 관여한 db 정보이다

                   database 항목이 null -> 현재 조회하고 있는 local DB를 의미

                   IN_OUT = OUT : 참조하는 NODE 정보로 database에 나오는 값이 db link name이다

                  이를 이용해 remote db의 dba_2pc_pending을 조회하여 관련 note 상태를 확인한다

          

                  SQL> select local_tran_id, global_tran_id, state, mixed, host, commit#

                             from dba_2pc_pending@db_link;

             

                            row를 확인하여 같은 분산 트랜잭션에 포함된 정보인지

                            global_tran_id를 이용해 확인한다

 

2) commit point site 확인

     일반적으로

         commit point site는 global coordinator의 DBA_2PC_NEIGHBORS의

         IN_OUT = OUT으로 나타나고

         INTERFACE 부분이 C로 나타나게 된다.

 

     commit point site가 중요한 이유는

        이 node의 local transaction 부분은 prepared 상태를 거치지 않아 in-doubt 상태가 안되므로

        distribute lock에 의해 조회나 DML 오류가 발생하지 않는다

           => 중요한 데이터를 포함하는 중심 node를 commit point site로 지정하는 것이 바람직 하다

 

3)  dba_2pc_pending의 mixed 컬럼 확인

      NO :  commit point site가 commit을 수행하기 전에 분산 트랜잭션이 fail되어

               commit point site가 rollback된 경우

               non-commit point site에서 prepared상태의 트랜잭션을 commit force 하면

               이것도 논리적으로

               consistency가 지켜지지 않은 것은 동일하나 이때는 mixed 컬럼이 no가 된다

               commit point site가 rollback되어 dba_2pc_pending에 row가 남지 않기 때문에 

               RECO mixed 상태를 인식하는 것이 불가능 하기 때문

 

     YES : commit point site가 이미 commit을 수행한 상태에서 분산 트랜잭션이 fail된 경우

               non-commit point site에서

               prepared상태의 transaction을  rollback force 시켜

               분산 트랜잭션의 consistency가 깨진 상태

               

               state 칼럼 : commit point site는 COMMITTED

                                  non-commit point site는 FORCED ROLLBACK으로 표시

 

 

 

①    state = COMMITED

        local DB 트랜잭션은 성공적으로 commit 됨, 어떤 작업도 수행할 필요 없음

        RECO에 의해 해당 node 자동 삭제됨. 지우지 못했다면 직접 삭제 가능

     

        sqlplus sys/manager

       

        SQL> exec dbms_transaction.purge_lost_db_entry(local_tran_id값);

       

        state=commit이면 commit point site가 commit된 후 임을 나타내므로

               state=COMMITTED로 나타나거나

               commit 후 정보다 지워져 dba_2pc_pending에 정보가 나타나지 않을 수 있다

        필요한 경우 dba_2pc_pending의 내용만 정리해 준다

 

②     state = PREPARED

        이 node에서 변경된 data가 속한 block에 distributed lock이 걸린 상태를 의미,

        이런 경우 data가 있는 block에 대한 모든 read/write가 ora-01591을 발생시킴

 

       관련 node의 dba_2pc_pending을 조회해서 정보가 없으면 commit point site이고

       이미 rollback되었음을 의미함.

       prepared 상태의 transaction을 rollback force 시켜준다

 

         SQL> rollback force ‘local_tran_id’ ; 

         SQL> commit force ‘local_tran_id’;       

                      node에 대한 정보가 있고 상태가 COMMITED면 commit 해주어야 한다

         SQL> commit force ‘tran_local_id’, ‘SCN’;

                   local_tran_id 뒤에 SCN를 지정할 수 있는데 제일 큰 SCN을 지정한다.

                   SCN값은 dba_2pc_pending의 commit# 에서 확인

                         -> 분산DB중 한 DB에서 incomplete recovery 필요한 경우

 

                   다른 DB도 일관성을 맞추기 위해 incomplete recovery를 이용할 수 있게 하기 위한 것

 

③     state = COLLECTING 

           distribute lock을 걸리 전단계에서 transaction이 비정상 종료 됨을 의미

           lock이 걸리기 전이므로 변경된 데이터는 rollback된 상태임

           이 경우엔 dba_2pc_pending에서 내용을 삭제 해주면 됨

           

            sqlplus sys/manager 

            SQL>exec dbms_transaction.purge_lost_db_entry(‘tran_local_id’);

 

④     state = FORCED ROLLBACK or FORCED COMMIT인 경우   

         이미 RECO or 디비 어드민이 rollback force or commit force를 하여 추가 수행 작업은 없음.

         RECO가 자동으로 ENTRY를 삭제해 줄 것이나 기다리지 않고 직접 삭제 할 수 있다

 

             sqlplus sys/manager 

             SQL>exec dbms_transaction.purge_lost_db_entry(‘tran_local_id’);

 

 

4) 불일치 사항을 파악하고 dba_2pc_pending을 정리한다

 

     분산 트랜잭션의 consistency가 무엇보다 중요한 경우라면 관계된

     nodedatabase를 모두 문제의 분산 트랜잭션이 수행되기 이전 상태로

     incomplete recovery를 수행하거나 할 수 있다. 

 

     분산 트랜잭션의 commit시 이용하는 commit SCN을 관계된

    모든 node들의 최대 SCN으로 이용하는 것이 바로 이러한 recovery를 위한 것이다

    이렇게 일부 database에서 SCN값이 이전 SCN에서 1씩 증가하는 것이 아니라

    큰 값으로 건너뛰어 다른 database와 같은 SCN을 유지하게 함으로써,

    이후에 incomplete recovery시에 관계된 node들이

    서로 동일한 SCN으로 recovery를 수행하면,

    모두 분산 트랜잭션 적용 이전이 되거나 or

    모두 이후가 되어 일관성을 유지할 수 있도록 해준다  

 

 

      MIXED=YES인 상태에서

          inconsistency를 받아들이고 DBA_2PC_PENDING view를 정리하려면

         다음과 같이 수행한다.

 

      sqlplus sys/manager 
      SQL>exec dbms_transaction.purge_mixed('local_tran_id');

 

     

      Automatic Undo mode에선 DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY 사용 전에

        "_smu_debug_mode"를 기술해 주어야 한다.

 

     

      alter session set "_smu_debug_mode" = 4;

     

      execute DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('local_tran_id');

 

 

 

 

                         

     출처: https://pat98.tistory.com/265 [pat98's always & forever:티스토리]

728x90