SQL 错误: ORA-01591: 锁被未决分布式事务处理 7.2.428982 持有
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.
处理办法:
rollback force ‘7.2.428982‘;--执行可能会比较慢
--执行完成后,查询DBA_2PC_PENDING,
select * from DBA_2PC_PENDING s where s.local_tran_id=‘7.2.428982‘;
select * from DBA_2PC_PENDING;
或者
delete from sys.pending_trans$ where local_tran_id = ‘7.2.428982‘;
delete from sys.pending_sessions$ where local_tran_id = ‘7.2.428982‘;
delete from sys.pending_sub_sessions$ where local_tran_id =‘7.2.428982‘;
commit;
commit force ‘657.7.39336‘
exec dbms_transaction.purge_lost_db_entry(‘657.7.39336‘);
select sess.sid, sess.serial#, lo.oracle_username, lo.os_user_name, ao.object_name, lo.locked_mode
from v$locked_object lo, dba_objects ao, v$session sess
where ao.object_id = lo.object_id and lo.session_id = sess.sid;
select * from v$session t1, v$locked_object t2 where t1.sid = t2.SESSION_ID;
select s.sid,s.machine,o.object_name,l.oracle_username,l.locked_mode, ‘ALTER SYSTEM KILL SESSION ‘‘‘||s.sid||‘, ‘||s.serial#||‘‘‘;‘ Command from v$locked_object l,v$session s,all_objects o where l.session_id=s.sid and l.object_id=o.object_id
SELECT A.OBJECT_ID, B.OBJECT_NAME, A.SESSION_ID, A.ORACLE_USERNAME, A.OS_USER_NAME, A.PROCESS, A.LOCKED_MODE FROM V$LOCKED_OBJECT A, DBA_OBJECTS B WHERE A.OBJECT_ID = B.OBJECT_ID;
SELECT T2.USERNAME, T2.SID, T2.SERIAL#, T2.LOGON_TIME FROM V$LOCKED_OBJECT T1, V$SESSION T2 WHERE T1.SESSION_ID = T2.SID ORDER BY T2.LOGON_TIME;
ALTER SYSTEM KILL SESSION ‘sid, serial#‘;
DBA_2PC_PENDING describes distributed transactions awaiting recovery.描述等待恢复的分布式事务。
LOCAL_TRAN_ID String of form: n.n.n; n is a number
GLOBAL_TRAN_ID Globally unique transaction ID
STATE Collecting, prepared, committed, forced commit, or forced rollback
MIXED YES indicates part of the transaction committed and part rolled back
ADVICE C for commit, R for rollback, else NULL
TRAN_COMMENT Text for commit work comment text
FAIL_TIME Value of SYSDATE when the row was inserted (transaction or system recovery)
FORCE_TIME Time of manual force decision (null if not forced locally)
RETRY_TIME Time automatic recovery (RECO) last tried to recover the transaction
OS_USER Operating system-specific name for the end-user
OS_TERMINAL Operating system-specific name for the end-user terminal
HOST Name of the host machine for the end-user
DB_USER Oracle user name of the end-user at the topmost database
COMMIT# Global commit number for committed transactions
这个错误是什么意思呢?
[[email protected] ~]$ oerr ora 01591
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.
两阶段提交(2PC)
两阶段提交协议可以保证数据的强一致性,许多分布式关系型数据管理系统采用此协议来完成分布式事务。它是协调所有分布式原子事务参与者,并决定提交或取消(回滚)的分布式算法。同时也是解决一致性问题的算法。该算法能够解决很多的临时性系统故障(包括进程、网络节点、通信等故障),被广泛地使用。但是,它并不能够通过配置来解决所有的故障,在某些情况下它还需要人为的参与才能解决问题。
顾名思义,两阶段提交分为以下两个阶段:
1)Prepare Phase (准备节点)
2)Commit Phase (提交阶段)
1)Prepare Phase
在请求阶段,协调者将通知事务参与者准备提交或取消事务,然后进入表决过程。在表决过程中,参与者将告知协调者自己的决策:同意(事务参与者本地作业执行成功)或取消(本地作业执行故障)。
为了完成准准备阶段,除了commit point site外,其它的数据库节点按照以下步骤执行:
每个节点检查自己是否被其它节点所引用,如果有,就通知这些节点准备提交(进入 Prepare阶段)。
每个节点检查自己运行的事务,如果发现本地运行的事务没有修改数据的操作(只读),则跳过后面的步骤,直接返回一个read only给全局协调器。
如果事务需要修改数据,则为事务分配相应的资源用于保证修改的正常进行。
当上面的工作都成功后,给全局协调器返回准备就绪的信息,反之,则返回失败的信息。
2) Commit Phase
在该阶段,协调者将基于第一个阶段的投票结果进行决策:提交或取消。当且仅当所有的参与者同意提交事务协调者才通知所有的参与者提交事务,否则协调者将通知所有的参与者取消事务。参与者在接收到协调者发来的消息后将执行响应的操作。
提交阶段按下面的步骤进行:
全局协调器通知 commit point site 进行提交。
commit point site 提交,完成后通知全局协调器。
全局协调器通知其它节点进行提交。
其它节点各自提交本地事务,完成后释放锁和资源。
其它节点通知全局协调器提交完成。
3)结束阶段
全局协调器通知commit point site说所有节点提交完成。
commit point site数据库释放和事务相关的所有资源,然后通知全局协调器。
全局协调器释放自己持有的资源。
分布式事务结束
一般情况下,两阶段提交机制都能较好的运行,当在事务进行过程中,有参与者宕机时,重启以后,可以通过询问其他参与者或者协调者,从而知道这个事务到底提交了没有。当然,这一切的前提都是各个参与者在进行每一步操作时,都会事先写入日志。
唯一一个两阶段提交不能解决的困境是:当协调者在发出commit 消息后宕机,而唯一收到这条命令的一个参与者也宕机了,这个时候这个事务就处于一个未知的状态,没有人知道这个事务到底是提交了还是未提交,从而需要数据库管理员的介入,防止数据库进入一个不一致的状态。当然,如果有一个前提是:所有节点或者网络的异常最终都会恢复,那么这个问题就不存在了,协调者和参与者最终会重启,其他节点也最终会收到commit 的信息。这也符合CAP理论。
http://blog.itpub.net/48010/viewspace-1016050/
下面简单介绍一下分布式事务。
分布式事务,简单来说,是指一个事务在本地和远程执行,本地需要等待确认远程的事务结束后,进行下一步本地的操作。如通过dblink update远程数据库的一行记录,如果在执行过程中网络异常,或者其他事件导致本地数据库无法得知远程数据库的执行情况,此时就会发生in doublt的报错。此时需要dba介入,且需要分多种情况进行处理。
分布式事务的Two-Phase Commit机制,会经历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他们已经完成commit,commit point site就能忘记(forget)这个事务。
3.2 commit point site在远程数据库上清除分布式事务信息。
3.3 commit point site通知Global Coordinator可以清除本地的分布式事务信息。
3.4 Global Coordinator清除分布式事务信息
以上3个阶段,在任何一个阶段的前、中、后发生失败都会导致two phase commit失败,一般来说,Oracle后台进程REC0会自动恢复事务,只有在分布式事务锁住的对象急需被访问,锁住的回滚段阻止了其他事务的使用,网络故障或CRASH的数据库的恢复需要很长的时间等情况出现时,才需要使用人工操作的方式来维护分布式事务,而分布式事务失败的情况也比较复杂,需要针对不同的情形采取相应的措施,Oracle中提供了视图dba_2pc_pending和dba_2pc_neighbors供用户查看分布式事务的相关信息,通常two phase commit失败有如下5种情况:
1.prepare阶段没准备好就失败了,global coordinator正在等待各个站点返回已准备好的通知,处于collecting状态,dba_2pc_pending试图中的state列的值是collecting,各个站点什么都没发生,无需执行任何操作,在本地数据库执行exec dbms_transaction.purge_lost_db_entry(’transaction_id’)清除in_doubt状态的分布式事务记录就可以了
2.prepare阶段完成时发生失败,global coordinator处于prepared状态,已经加上分布锁,等待提交,远程commit point site已经自动回滚,此时需要在global coordinator上执行rollback force ‘transaction_id’,然后清除in_doubt状态的分布式事务记录
3.commit point site执行commit完成后其他站点尚未commit时发生失败,这时需要在其他站点执行commit force ‘transaction_id’,‘commit#’,注意后面的commit#使用较高的commit#,可以查询各个站点的dba_2pc_pending试图的commit#列得到,然后清除in_doubt状态的分布式事务记录
4.所有站点commit成功,进入forget阶段时发生失败,数据已经一致,只需在各站点清除in_doubt状态的分布式事务记录就可以了
5.commit point site完成forget阶段,其他站点没完成forget,只需在其他站点清除in_doubt状态的分布式事务记录就可以了