この章の内容は、次のとおりです。
分散トランザクションでどのノードが最初にコミットされるかは、最も高いコミット・ポイント強度を持つデータベースによって決まります。各ノードのコミット・ポイント強度を指定するときは、準備フェーズまたはコミット・フェーズ中に障害が発生した場合に最も重要なサーバーがブロックされないようにしてください。ノードのコミット・ポイント強度は、COMMIT_POINT_STRENGTH
初期化パラメータによって指定します。
デフォルト値は、オペレーティング・システムによって異なります。値の範囲は、0(ゼロ)から255までの任意の整数です。たとえば、データベースのコミット・ポイント強度を200に設定するには、そのデータベースの初期化パラメータ・ファイルに次の行を追加します。
COMMIT_POINT_STRENGTH = 200
コミット・ポイント強度は、分散トランザクションでコミット・ポイント・サイトを決定する際にのみ使用されます。
データベースのコミット・ポイント強度を設定するときは、次の点を考慮してください。
コミット・ポイント・サイトにはトランザクションのステータスに関する情報が格納されます。他のノードがトランザクションのステータスに関する情報を必要とする場合に備えて、コミット・ポイント・サイトには、信頼性が低下したり、使用できなくなったりする頻度の高いノードを使用しないでください。
データベースのコミット・ポイント強度は、データベース内の重要な共有データの量に比例するように設定してください。たとえば、メインフレーム・コンピュータのデータベースは、一般にPCのデータベースよりも多くのデータをユーザー間で共有しています。したがって、メインフレームのコミット・ポイント強度は、PCのコミット・ポイント強度よりも高い値に設定します。
トランザクションの命名が可能です。この機能は、特定の分散トランザクションを識別する際に便利であり、同じ目的のCOMMIT COMMENT
文にかわるものです。
トランザクションに命名するにはSET TRANSACTION...NAME
文を使用します。次に例を示します。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE NAME 'update inventory checkpoint 0';
この例は、SERIALIZABLE
に等しい分離レベルを持つ新しいトランザクションをユーザーが開始し、それに'update inventory checkpoint 0'
という名前を付けたことを示しています。
分散トランザクションでは、トランザクションがコミットされるときに、名前が参加サイトに送られます。トランザクション名が存在する場合は、COMMIT COMMENT
があっても無視されます。
トランザクション名は、V$TRANSACTION
ビューのNAME
列に表示され、トランザクションがコミットされると、DBA_2PC_PENDINGビューのTRAN_COMMENT
フィールドに表示されます。
各データベースのデータ・ディクショナリには、オープンしているすべての分散トランザクションに関する情報が格納されています。データ・ディクショナリの表とビューを使用すると、トランザクションに関する情報を取得できます。この項の内容は次のとおりです。
次のビューには、ローカル・データベースで定義され、データ・ディクショナリに格納されているデータベース・リンクが表示されます。
ビュー | 目的 |
---|---|
DBA_2PC_PENDING |
インダウト分散トランザクションがすべてリストされます。このビューには、インダウト・トランザクションが移入されるまで何もデータが入っていません。トランザクションが解決された後、ビューはパージされます。 |
このビューは、特定のトランザクションIDのグローバル・コミット番号を判断するために使用します。このグローバル・コミット番号は、インダウト・トランザクションを手動で解決するときに使用できます。
関連性の最も高い列を次の表に示します(ビューのすべての列の詳細は、『Oracle Databaseリファレンス』を参照してください)。
表35-1 DBA_2PC_PENDING
DBA_2PC_PENDING
の関連情報を問い合せるには、次のスクリプトpending_txn_script
を実行します(出力例も含まれています)。
COL LOCAL_TRAN_ID FORMAT A13 COL GLOBAL_TRAN_ID FORMAT A30 COL STATE FORMAT A8 COL MIXED FORMAT A3 COL HOST FORMAT A10 COL COMMIT# FORMAT A10 SELECT LOCAL_TRAN_ID, GLOBAL_TRAN_ID, STATE, MIXED, HOST, COMMIT# FROM DBA_2PC_PENDING / SQL> @pending_txn_script LOCAL_TRAN_ID GLOBAL_TRAN_ID STATE MIX HOST COMMIT# ------------- ------------------------------ -------- --- ---------- ---------- 1.15.870 HQ.EXAMPLE.COM.ef192da4.1.15.870 commit no dlsun183 115499
この出力は、ローカル・トランザクション1.15.870
がこのノードではコミットを完了しているものの、他の1つ以上のノードで保留している可能性があることを示しています。LOCAL_TRAN_ID
とGLOBAL_TRAN_ID
のローカル部分が同じなので、このノードはトランザクションのグローバル・コーディネータです。
次のビューには、リモート・クライアントから受信されるインダウト・トランザクションと、リモート・サーバーに送信されるインダウト・トランザクションが表示されます。
トランザクションがインダウトのときは、セッション・ツリー内のどのノードがどのロールを実行しているのかを判断することが必要な場合があります。このビューを使用すると、次のことが判断できます。
特定のトランザクションのすべての受信接続と送信接続。
ノードが特定のトランザクションのコミット・ポイント・サイトかどうか。
ノードが特定のトランザクションのグローバル・コーディネータかどうか(ノードのローカル・トランザクションIDとグローバル・トランザクションIDが同じかどうかで判断する)。
関連性の最も高い列を次の表に示します(ビューのすべての列の詳細は、『Oracle Databaseリファレンス』を参照してください)。
表35-2 DBA_2PC_NEIGHBORS
列 | 説明 |
---|---|
|
「integer.integer.integer」という書式のローカル・トランザクション識別子。 注意: 接続の |
|
受信トランザクションの場合は |
|
受信トランザクションの場合は、このローカル・ノードから情報を要求したクライアント・データベースの名前です。送信トランザクションの場合は、リモート・サーバーの情報へのアクセスに使用されたデータベース・リンクの名前です。 |
|
受信トランザクションの場合は、リモート・データベース・リンクによる接続で使用されるローカル・アカウントです。送信トランザクションの場合は、データベース・リンクの所有者です。 |
|
|
DBA_2PC_PENDING
の関連情報を問い合せるには、次のスクリプトneighbors_script
を実行します(出力例も含まれています)。
COL LOCAL_TRAN_ID FORMAT A13 COL IN_OUT FORMAT A6 COL DATABASE FORMAT A25 COL DBUSER_OWNER FORMAT A15 COL INTERFACE FORMAT A3 SELECT LOCAL_TRAN_ID, IN_OUT, DATABASE, DBUSER_OWNER, INTERFACE FROM DBA_2PC_NEIGHBORS / SQL> CONNECT SYS@hq.example.com AS SYSDBA SQL> @neighbors_script LOCAL_TRAN_ID IN_OUT DATABASE DBUSER_OWNER INT ------------- ------ ------------------------- --------------- --- 1.15.870 out SALES.EXAMPLE.COM SYS C
この出力は、ローカル・ノードからリモート・サーバーsales
に、トランザクション1.15.870
をコミットするように送信リクエストが送られたことを示しています。sales
がトランザクションをコミットし、他にコミットしたノードがない場合は、常に最初にコミットするのがコミット・ポイント・サイトであるため、sales
がコミット・ポイント・サイトになります。
2フェーズ・コミットの間に障害が発生すると、トランザクションはインダウトになります。分散トランザクションがインダウトになる要因は、次のとおりです。
Oracle Databaseソフトウェアを実行しているサーバー・システムがクラッシュした。
分散処理に関係している複数のOracle Database間のネットワーク接続が切断された。
未処理のソフトウェア・エラーが発生した。
ローカルのインダウト分散トランザクションは、手動で強制的にコミットまたはロールバックできます。この操作では一貫性の問題が生じる可能性があるため、特定の条件が成り立つとき以外は実行しないでください。
この項の内容は次のとおりです。
分散トランザクションをコミットするユーザー・アプリケーションには、次のいずれかのエラー・メッセージによって問題が通知されます。
ORA-02050: transaction ID rolled back, some remote dbs may be in-doubt ORA-02053: transaction ID committed, some remote dbs may be in-doubt ORA-02054: transaction ID in-doubt
アプリケーションでこれらのエラーを受け取った場合は、トランザクションに関する情報を保存するようにしてください。この情報は、後で分散トランザクションの手動リカバリが必要になった場合に使用できます。
ネットワークまたはシステムの障害のために、任意のノードでインダウト分散トランザクションが1つ以上発生した場合でも、そのノードの管理者がなんらかの処理を実行する必要はありません。ネットワークやシステムの障害が解決した後、データベースの自動リカバリ機能によって、セッション・ツリーのすべてのノードが同じ結果になるように(つまり、すべてコミットされるかすべてロールバックされる)、すべてのインダウト・トランザクションの処理が透過的に完了します。
ただし、障害が長期にわたる場合には、トランザクションを強制的にコミットまたはロールバックすることで、ロックされたデータをすべて解放できます。アプリケーションは、この操作を想定しておく必要があります。
特定のインダウト・トランザクションを手動でオーバーライドするのは、次のいずれかの条件が存在する場合のみです。
インダウト・トランザクションが他のトランザクションに必要なデータをロックしている場合。この状況は、ORA-01591
エラー・メッセージによってユーザーのトランザクションが妨げられたときに起こります。
インダウト・トランザクションは、UNDOセグメントのエクステントが他のトランザクションによって使用されることを防ぎます。インダウト分散トランザクションのローカル・トランザクションIDの最初の部分は、データ・ディクショナリ・ビューDBA_2PC_PENDING
でリストされるUNDOセグメントのIDに対応します。
2フェーズ・コミットの各フェーズの完了を妨げている障害を許容される時間範囲内で訂正できない場合。このような例としては、通信ネットワークやデータベースの損傷など、リカバリに長い時間を要する障害があります。
通常、インダウト分散トランザクションをローカルで強制する場合は、別の場所の管理者と相談した上で決断する必要があります。判断を誤るとデータベースの一貫性が損われ、トレースが困難で手動での修正が必要となる恐れがあります。
これらの条件のいずれも当てはまらない場合、データベースの自動リカバリ機能を常に許可し、トランザクションを完了してください。しかし、前述のいずれかの条件に当てはまる場合には、インダウト・トランザクションのローカルでの修正を検討してください。
トランザクションの強制完了を決めた場合は、次の目的に留意しながら、使用可能な情報を分析します。
DBA_2PC_PENDING
ビューを使用し、トランザクションをコミットまたはロールバックしたノードを探します。トランザクションをすでに解決しているノードが見つかった場合は、そのノードで実行された処理に従うことができます。
DBA_2PC_PENDING
のTRAN_COMMENT
列に、対象の分散トランザクションに関するなんらかの情報が与えられていないかを確認します。COMMIT
文のCOMMENT
句にコメントが含まれているか、またはトランザクションに命名している場合は、トランザクションがコミットされると、トランザクション名がTRAN_COMMENT
フィールドに設定されます。
たとえば、インダウト分散トランザクションのコメントで、トランザクションの開始元とタイプを示すことができます。
COMMIT COMMENT 'Finance/Accts_pay/Trans_type 10B';
また、この情報をトランザクション名として提供するために、SET TRANSACTION...NAME
文を使用することも可能です。
DBA_2PC_PENDING
のADVICE
列に、対象の分散トランザクションに関するなんらかの情報が与えられていないかを確認します。アプリケーションでALTER SESSION
文のADVISE
句を使用すれば、分散トランザクションの別々の部分を強制的にコミットまたはロールバックする際のアドバイスを規定できます。
準備フェーズ中に各ノードに送られたアドバイスは、現行トランザクション内でそのデータベースに対し最新のDML文が実行されたときに有効なアドバイスです。
たとえば、あるノードのemp
表から別のノードのemp
表に従業員レコードを移動する分散トランザクションを考えます。次の一連のSQL文を追加することによって、管理者が各ノードで個別にインダウト・トランザクションを強制的に完了した場合でも、トランザクションでレコードを保護できます。
ALTER SESSION ADVISE COMMIT; INSERT INTO emp@hq ... ; /*advice to commit at HQ */ ALTER SESSION ADVISE ROLLBACK; DELETE FROM emp@sales ... ; /*advice to roll back at SALES*/ ALTER SESSION ADVISE NOTHING;
与えられたアドバイスに従ってインダウト・トランザクションを手動で強制的に完了すると、最悪の場合、各ノードに従業員レコードがコピーされ、消去できなくなる可能性があります。
COMMIT
文またはROLLBACK
文に、FORCE
オプションと、コミットまたはロールバックするインダウト・トランザクションのローカル・トランザクションIDまたはグローバル・トランザクションIDを示すテキスト文字列を指定します。
注意: 以降のすべての例で、トランザクションはローカル・ノードでコミットまたはロールバックされます。ローカルのペンディング・トランザクション表では、このトランザクションの行のSTATE 列に強制コミットまたは強制終了の値が記録されます。 |
この項の内容は次のとおりです。
トランザクションのコミットを試みる前に、適正な権限を持っていることを確認してください。次の要件に注意してください。
トランザクションをコミットするユーザー | 必要な権限 |
---|---|
管理者 | FORCE TRANSACTION |
別のユーザー | FORCE ANY TRANSACTION |
次のSQL文は、インダウト・トランザクションをコミットします。
COMMIT FORCE 'transaction_id';
変数transaction_idは、DBA_2PC_PENDING
データ・ディクショナリ・ビューのLOCAL_TRAN_ID
列またはGLOBAL_TRAN_ID
列のどちらかで指定されているトランザクション識別子です。
たとえば、DBA_2PC_PENDING
を問い合せて、分散トランザクションのLOCAL_TRAN_ID
が1:45.13
であることを確認するとします。
そして、次のSQL文を発行し、このインダウト・トランザクションのコミットを強制実行します。
COMMIT FORCE '1.45.13';
必要であれば、トランザクションを強制的にコミットするときに、トランザクションのSCNを指定することもできます。この機能を使用すると、他のノードでトランザクションがコミットされたときに割り当てられたSCNを使用して、インダウト・トランザクションをコミットできます。
これにより、障害が発生した場合でも、分散トランザクションのコミット時間の同期を保つことができます。SCNは、別のノードですでにコミットされた同じトランザクションのSCNが判別できるときのみ指定してください。
たとえば、次のグローバル・トランザクションIDを使用してトランザクションを手動でコミットするとします。
SALES.EXAMPLE.COM.55d1c563.1.93.29
まず、対象のトランザクションに関係しているリモート・データベースのDBA_2PC_PENDING
ビューを問い合せます。次に、そのノードでトランザクションのコミットに使用されたSCNをメモします。そして、ローカル・ノードでトランザクションをコミットするときにこのSCNを指定します。たとえば、SCNが829381993
の場合は、次の文を発行します。
COMMIT FORCE 'SALES.EXAMPLE.COM.55d1c563.1.93.29', 829381993;
関連項目: COMMIT文の使用の詳細は、『Oracle Database SQL言語リファレンス』 を参照してください。 |
インダウト分散トランザクションのロールバックを試みる前に、適正な権限を持っていることを確認してください。次の要件に注意してください。
トランザクションをコミットするユーザー | 必要な権限 |
---|---|
管理者 | FORCE TRANSACTION |
別のユーザー | FORCE ANY TRANSACTION |
次のSQL文は、インダウト・トランザクションをロールバックします。
ROLLBACK FORCE 'transaction_id';
変数transaction_idは、DBA_2PC_PENDING
データ・ディクショナリ・ビューのLOCAL_TRAN_ID
列またはGLOBAL_TRAN_ID
列のどちらかで指定されているトランザクション識別子です。
たとえば、ローカル・トランザクションIDが2.9.4
のインダウト・トランザクションをロールバックするには、次の文を使用します。
ROLLBACK FORCE '2.9.4';
注意: インダウト・トランザクションをセーブポイントまでロールバックすることはできません。 |
関連項目: ROLLBACK文の詳細は、『Oracle Database SQL言語リファレンス』 を参照してください。 |
インダウト・トランザクションは、RECO(リカバラ・プロセス)によってリカバリされる前に、DBA_2PC_PENDING.STATE
列にCOLLECTING
、COMMITTED
またはPREPARED
として表示されます。COMMIT FORCE
またはROLLBACK FORCE
を使用してインダウト・トランザクションを強制的に完了すると、FORCED COMMIT
またはFORCED ROLLBACK
の状態になることがあります。
自動リカバリでは通常、これらの状態にあるエントリが削除されます。唯一の例外として、リカバリ時に、トランザクション内の他のサイトと一貫性のない状態にある強制トランザクションが検出されるときがあります。この場合は、エントリが表内に残る可能性があり、DBA_2PC_PENDING
のMIXED
列の値がYES
になります。これらのエントリは、DBMS_TRANSACTION.PURGE_MIXED
プロシージャを使用してクリーン・アップできます。
リモート・データベースが永続的に失われたために自動リカバリが不可能な場合は、データベースを再作成しても再作成時に新しいデータベースIDが割り当てられるため、リカバリではそのデータベースを識別できません。このような場合、DBMS_TRANSACTION
パッケージのPURGE_LOST_DB_ENTRY
プロシージャを使用してエントリをクリーン・アップする必要があります。このエントリによってデータベース・リソースが保持されることはないため、エントリのクリーン・アップを急ぐ必要はありません。
関連項目: DBMS_TRANSACTIONパッケージの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』 を参照してください。 |
エントリをデータ・ディクショナリから手動で削除するには、次の構文を使用します(ここで、trans_idはトランザクションの識別子を表します)。
DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('trans_id');
たとえば、保留中の分散トランザクション1.44.99
をパージするには、SQL*Plusで次の文を入力します。
EXECUTE DBMS_TRANSACTION.PURGE_LOST_DB_ENTRY('1.44.99');
このプロシージャは、自動リカバリによってトランザクションを解決できないほどの大幅な再構成を行った場合にのみ実行してください。たとえば、次のような場合です。
リモート・データベースが完全に失われた場合
ソフトウェアを再構成した結果、2フェーズ・コミットの機能がなくなった場合
TPMonitorなどの外部トランザクション・コーディネータからの情報が失われた場合
次の表は、分散トランザクションに関する各種の状態と、それに対して管理者が実行すべき処理を示したものです。
STATE列 | グローバル・トランザクションの状態 | ローカル・トランザクションの状態 | 通常の処理 | 代替処理 |
---|---|---|---|---|
Collecting | ロールバック | ロールバック | なし | PURGE_LOST_DB_ENTRY (自動リカバリでトランザクションを解決できない場合のみ) |
Committed | Committed | Committed | なし | PURGE_LOST_DB_ENTRY (自動リカバリでトランザクションを解決できない場合のみ) |
Prepared | 不明 | Prepared | なし | 強制コミットまたは強制ロールバック |
Forced commit | 不明 | Committed | なし | PURGE_LOST_DB_ENTRY (自動リカバリでトランザクションを解決できない場合のみ) |
Forced rollback | 不明 | ロールバック | なし | PURGE_LOST_DB_ENTRY (自動リカバリでトランザクションを解決できない場合のみ) |
Forced commit | 混合 | Committed | 非一貫性部分を手動で削除してからPURGE_MIXED を使用する |
- |
Forced rollback | 混合 | ロールバック | 非一貫性部分を手動で削除してからPURGE_MIXED を使用する |
- |
図35-1は、分散トランザクションのコミット中の障害を示しています。この障害例では、準備フェーズは完了しています。しかし、コミット・フェーズ時に、コミット・ポイント・サイトがトランザクションをコミットしていても、コミット・ポイント・サイトのコミット確認がグローバル・コーディネータに到達しません。インダウト・トランザクションは他のトランザクションにとっても重要なものであるため、在庫データはロックされており、アクセスできません。また、インダウト・トランザクションがコミットまたはロールバックされるまで、ロックが必ず保持されます。
次の手順に従って、インダウト・トランザクションのローカル部分を手動で強制完了できます。詳細は、以降の項を参照してください。
手順3: ローカル・ノードでのDBA_2PC_NEIGHBORSの問合せ
手順4: 全ノードでのデータ・ディクショナリ・ビューの問合せ
手順6: DBA_2PC_PENDINGを使用したMIXED結果のチェック
インダウト・トランザクションのロックと競合を起こしているローカル・データベース・システムのユーザーは、次のエラー・メッセージを受け取ります。
ORA-01591: lock held by in-doubt distributed transaction 1.21.17
この場合、1.21.17
はインダウト分散トランザクションのローカル・トランザクションIDです。どのインダウト・トランザクションを強制処理すればよいかを特定するために、問題を報告したユーザーからこのID番号を聞き、記録しておきます。
SQL*Plusを使用してwarehouse
に接続した後、ローカルのDBA_2PC_PENDING
データ・ディクショナリ・ビューを問い合せて、インダウト・トランザクションに関する情報を取得します。
CONNECT SYS@warehouse.example.com AS SYSDBA SELECT * FROM DBA_2PC_PENDING WHERE LOCAL_TRAN_ID = '1.21.17';
データベースは次の情報を返します。
Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.21.17 GLOBAL_TRAN_ID SALES.EXAMPLE.COM.55d1c563.1.93.29 STATE prepared MIXED no ADVICE TRAN_COMMENT Sales/New Order/Trans_type 10B FAIL_TIME 31-MAY-91 FORCE_TIME RETRY_TIME 31-MAY-91 OS_USER SWILLIAMS OS_TERMINAL TWA139: HOST system1 DB_USER SWILLIAMS COMMIT#
グローバル・トランザクションIDは、分散トランザクションのすべてのノードで同一である共通のトランザクションIDです。次のような書式で記録されています。
global_database_name
.hhhhhhhh.local
_transaction_id
説明:
global_database_name
は、グローバル・コーディネータのデータベース名です。
hhhhhhhh
は、グローバル・コーディネータの内部データベース識別子(16進値)です。
local_transaction_id
は、グローバル・コーディネータで割り当てられた、対応するローカル・トランザクションIDです。
グローバル・コーディネータでは、グローバル・トランザクションIDの最後の部分とローカル・トランザクションIDが一致します。この例では、これらの番号が一致していないため、warehouse
がグローバル・コーディネータではないことがわかります。
LOCAL_TRAN_ID 1.21.17 GLOBAL_TRAN_ID ... 1.93.29
このノードのトランザクションは、準備完了状態です。
STATE prepared
したがって、warehouse
は、自身のコーディネータからコミット要求またはロールバック要求が送られてくるのを待っています。
トランザクションのコメントまたはアドバイスに、このトランザクションに関する情報が含まれている可能性があります。トランザクションに関する情報が含まれていれば、そのコメントを利用します。この例では、トランザクションのコメントに開始元とトランザクション・タイプが含まれています。
TRAN_COMMENT Sales/New Order/Trans_type 10B
また、SET TRANSACTION...NAME
文によって、トランザクション名として提供されている可能性もあります。
この情報から、トランザクションのローカル部分をコミットすべきか、またはロールバックすべきかを決める際に役立つ情報を得ることができます。インダウト・トランザクションに有益なコメントが付けられていない場合は、その他の管理作業を実行し、セッション・ツリーをトレースして、トランザクションをすでに解決しているノードを探す必要があります。
この手順の目的は、セッション・ツリーを探索してコーディネータを見つけ、最終的にグローバル・コーディネータに到達することです。それと同時に、トランザクションをすでに解決しているコーディネータが見つかる場合もあります。見つからない場合は、最終的にコミット・ポイント・サイトを探し出します(コミット・ポイント・サイトでは、常にインダウト・トランザクションが解決されています)。セッション・ツリーをトレースするには、各ノードのDBA_2PC_NEIGHBORS
ビューを問い合せます。
この例では、warehouse
データベースでこのビューを問い合せます。
CONNECT SYS@warehouse.example.com AS SYSDBA SELECT * FROM DBA_2PC_NEIGHBORS WHERE LOCAL_TRAN_ID = '1.21.17' ORDER BY SESS#, IN_OUT; Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.21.17 IN_OUT in DATABASE SALES.EXAMPLE.COM DBUSER_OWNER SWILLIAMS INTERFACE N DBID 000003F4 SESS# 1 BRANCH 0100
DBA_2PC_NEIGHBORS
ビューは、インダウト・トランザクションに対応付けられた接続に関する情報を提供します。情報は、接続が受信(IN_OUT = in
)か送信(IN_OUT = out
)かによって異なります。
IN_OUT | 意味 | DATABASE | DBUSER_OWNER |
---|---|---|---|
in | このノードは別のノードのサーバーです。 | このノードに接続しているクライアント・データベースの名前がリストされます。 | インダウト・トランザクションに対応するデータベース・リンク接続のローカル・アカウントがリストされます。 |
out | このノードは他のサーバーのクライアントです。 | リモート・ノードに接続しているデータベース・リンクの名前がリストされます。 | インダウト・トランザクションのデータベース・リンクの所有者がリストされます。 |
この例では、IN_OUT
列によって、warehouse
データベースがsales
クライアント(DATABASE列に示されている)のサーバーであることがわかります。
IN_OUT in DATABASE SALES.EXAMPLE.COM
warehouse
への接続は、swilliams
アカウント(DBUSER_OWNER
列に示されている)からのデータベース・リンクを介して確立されています。
DBUSER_OWNER SWILLIAMS
この時点で、各設置ノードの管理者に連絡を取り、グローバル・トランザクションIDを使用して手順2および3を繰り返すように各管理者に依頼できます。
注意: これらのノードに別のネットワークを介して直接接続できる場合は、手順2および3を独力で実行できます。 |
たとえば、sales
およびhq
で手順2および3を実行すると、次の結果が返されます。
この段階では、sales
の管理者がDBA_2PC_PENDING
データ・ディクショナリ・ビューを問い合せます。
SQL> CONNECT SYS@sales.example.com AS SYSDBA SQL> SELECT * FROM DBA_2PC_PENDING > WHERE GLOBAL_TRAN_ID = 'SALES.EXAMPLE.COM.55d1c563.1.93.29'; Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.93.29 GLOBAL_TRAN_ID SALES.EXAMPLE.COM.55d1c563.1.93.29 STATE prepared MIXED no ADVICE TRAN_COMMENT Sales/New Order/Trans_type 10B FAIL_TIME 31-MAY-91 FORCE_TIME RETRY_TIME 31-MAY-91 OS_USER SWILLIAMS OS_TERMINAL TWA139: HOST system1 DB_USER SWILLIAMS COMMIT#
次に、sales
の管理者はDBA_2PC_NEIGHBORS
を問い合せて、グローバル・コーディネータ、ローカル・コーディネータおよびコミット・ポイント・サイトを判別します。
SELECT * FROM DBA_2PC_NEIGHBORS WHERE GLOBAL_TRAN_ID = 'SALES.EXAMPLE.COM.55d1c563.1.93.29' ORDER BY SESS#, IN_OUT;
この問合せは、次の3行を返します。
warehouse
への接続
hq
への接続
ユーザーが確立した接続
warehouse
接続の行に対応する情報を、書式を変えて示すと次のようになります。
Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.93.29 IN_OUT OUT DATABASE WAREHOUSE.EXAMPLE.COM DBUSER_OWNER SWILLIAMS INTERFACE N DBID 55d1c563 SESS# 1 BRANCH 1
hq
接続の行に対応する情報を、書式を変えて示すと次のようになります。
Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.93.29 IN_OUT OUT DATABASE HQ.EXAMPLE.COM DBUSER_OWNER ALLEN INTERFACE C DBID 00000390 SESS# 1 BRANCH 1
前の問合せから得られた情報によって、次のことがわかります。
sales
は、ローカル・トランザクションIDとグローバル・トランザクションIDが一致しているため、グローバル・コーディネータです。
このノードからは送信接続が2つ確立されていますが、受信接続は確立されていません。したがって、sales
は別のノードのサーバーではありません。
コミット・ポイント・サイトは、hq
またはそのサーバーの1つです。
この段階では、hq
の管理者がDBA_2PC_PENDING
データ・ディクショナリ・ビューを問い合せます。
SELECT * FROM DBA_2PC_PENDING@hq.example.com WHERE GLOBAL_TRAN_ID = 'SALES.EXAMPLE.COM.55d1c563.1.93.29'; Column Name Value ---------------------- -------------------------------------- LOCAL_TRAN_ID 1.45.13 GLOBAL_TRAN_ID SALES.EXAMPLE.COM.55d1c563.1.93.29 STATE COMMIT MIXED NO ACTION TRAN_COMMENT Sales/New Order/Trans_type 10B FAIL_TIME 31-MAY-91 FORCE_TIME RETRY_TIME 31-MAY-91 OS_USER SWILLIAMS OS_TERMINAL TWA139: HOST SYSTEM1 DB_USER SWILLIAMS COMMIT# 129314
この時点で、トランザクションを解決しているノードが見つかりました。ビューが示しているように、このノードではコミットが完了しており、コミットID番号が割り当てられています。
STATE COMMIT COMMIT# 129314
したがって、自分のローカル・データベースでインダウト・トランザクションを強制的にコミットできます。この調査結果を他の管理者に伝えれば、他の場所での解決に役立つ可能性があります。
sales
データベースの管理者と連絡を取り、グローバルIDを使用してインダウト・トランザクションを手動でコミットするように依頼します。
SQL> CONNECT SYS@sales.example.com AS SYSDBA SQL> COMMIT FORCE 'SALES.EXAMPLE.COM.55d1c563.1.93.29';
同時に、warehouse
データベースの管理者として、グローバルIDを使用してインダウト・トランザクションを手動でコミットします。
SQL> CONNECT SYS@warehouse.example.com AS SYSDBA SQL> COMMIT FORCE 'SALES.EXAMPLE.COM.55d1c563.1.93.29';
トランザクションを手動で強制的にコミットまたはロールバックした後も、ペンディング・トランザクション表の対応する行はそのまま残っています。トランザクションの状態は、トランザクションをどのように強制完了したかに応じて変わります。
Oracle Databaseには、必ずペンディング・トランザクション表があります。これは、2フェーズ・コミットの各フェーズの進行に従って分散トランザクションに関する情報を格納する特別な表です。データベースのペンディング・トランザクション表は、DBA_2PC_PENDING
データ・ディクショナリ・ビューを介して問い合せることができます(詳細は表35-1を参照)。
また、ペンディング・トランザクション表で特に重要なものとして、DBA_2PC_PENDING.MIXED
に示されるMIXED結果フラグがあります。ペンディング・トランザクションを強制的にコミットまたはロールバックする場合は、選択を誤る可能性があります。たとえば、ローカル管理者がトランザクションをロールバックしたにもかからわず、他のノードではそのトランザクションをコミットしてしまうといったことが考えられます。このような誤った判断は自動的に検出され、対応するペンディング・トランザクションのレコードに損傷フラグが設定されます(MIXED=yes
)。
RECOバックグラウンド・プロセスは、ペンディング・トランザクション表の情報を使用して、インダウト・トランザクションの状態を最終決定します。また、管理者がペンディング・トランザクション表の情報を使用して、保留中の分散トランザクションの自動リカバリ手順を手動で上書きすることもできます。
RECOによって自動解決されたトランザクションはすべて、保留中のトランザクション表から削除される。また、管理者によって正しく解決されたインダウト・トランザクションに関する情報も、RECOが通信を再確立したときにチェックされて、すべてペンディング・トランザクション表から自動的に削除されます。ただし、管理者が解決したことによってノード間にまたがってMIXEDの結果が生じた行は、DBMS_TRANSACTIONS.PURGE_MIXED
を使用して手動で削除しないかぎり、関係しているすべてのノードのペンディング・トランザクション表にそのまま残ります。
SQL文を発行すると、データベースは文を正常に実行するために必要なリソースのロックを試みます。しかし、要求されたデータが、コミットされていない他のトランザクションの文によって現在保持されていて、長時間ロックされたままになっていると、タイムアウトが発生します。
データ・アクセスの障害に関しては、次の事例について考慮してください。
リモート・データベースのロックを必要とするDML文は、要求したデータのロックを別のトランザクションが所有している場合にブロックされる可能性があります。このようなロックによってSQL文の要求がブロックされ続けると、次の一連のイベントが発生します。
タイムアウトが発生します。
データベースは文をロールバックします。
ORA-02049: time-out: distributed transaction waiting for lock
トランザクションによってデータは変更されていないので、タイムアウトの結果として必要な処理はありません。アプリケーションでは、デッドロックが発生したものとして処理を継続してください。文を実行したユーザーは、後で同じ文の再実行を試みることができます。それでもロックが続く場合には、ユーザーは管理者に連絡して問題を報告してください。
ローカル・データベースのロックを必要とする問合せまたはDML文は、インダウト分散トランザクションによるリソースのロックのために無期限にブロックされる可能性があります。この場合、データベースは次のエラー・メッセージを発行します。
ORA-01591: lock held by in-doubt distributed transaction identifier
この場合、データベースはSQL文をただちにロールバックします。文を実行したユーザーは、後で同じ文の再実行を試みることができます。ロックが持続する場合、ユーザーは管理者に連絡して、インダウト分散トランザクションのIDなども含めて問題を報告する必要があります。
2フェーズ・コミットの重要な部分の処理中に障害が発生する確率は低いため、このような状況が起こる可能性はほとんどありません。仮にこのような障害が発生した場合でも、ネットワーク障害やシステム障害から迅速にリカバリできれば、手動で介入しなくても問題は自動的に解決されます。したがって、この種の問題は、ユーザーやデータベース管理者に検出される前に解決されるのが普通です。
分散トランザクションの障害は、次のような理由で強制的に発生させることができます。
RECOがトランザクションのローカル部分を自動的に解決する様子を観察するため
インダウト分散トランザクションの手動解決の演習を行い、その結果を観察するため
ここでは、使用可能な機能とその操作に必要な手順を説明します。
COMMIT
文のCOMMENT
パラメータには、コメントを挿入できます。分散トランザクションの2フェーズ・コミットのフェーズ時に意図して障害を発生させるには、COMMENT
パラメータに、次のコメントを挿入します。
COMMIT COMMENT 'ORA-2PC-CRASH-TEST-n';
コメント内のnには、次の整数のいずれかが入ります。
n | 影響 |
---|---|
1 | 収集後コミット・ポイントをクラッシュ |
2 | 収集後コミット・ポイント・サイト以外をクラッシュ |
3 | 準備前にクラッシュ(コミット・ポイント・サイト以外) |
4 | 準備後にクラッシュ(コミット・ポイント・サイト以外) |
5 | コミット前にコミット・ポイント・サイトをクラッシュ |
6 | コミット後にコミット・ポイント・サイトをクラッシュ |
7 | コミット前にコミット・ポイント・サイト以外をクラッシュ |
8 | コミット後にコミット・ポイント・サイト以外をクラッシュ |
9 | 情報消去前にコミット・ポイント・サイトをクラッシュ |
10 | 情報消去前にコミット・ポイント・サイト以外をクラッシュ |
たとえば、ローカルのコミット・ポイント強度がリモートのコミット・ポイント強度よりも高く、双方のノードが更新されている場合、次の文では、次のメッセージが返されます。
COMMIT COMMENT 'ORA-2PC-CRASH-TEST-7'; ORA-02054: transaction 1.93.29 in-doubt ORA-02059: ORA_CRASH_TEST_7 in commit comment
この時点で、インダウト分散トランザクションがDBA_2PC_PENDING
ビューに表示されます。対応している場合は、RECOがそのトランザクションを自動的に解決します。
Oracle DatabaseインスタンスのRECOバックグラウンド・プロセスは、分散トランザクションに伴う障害を自動的に解決します。ノードのRECOバックグラウンド・プロセスは、時間間隔を指数関数的に広げながら、インダウト分散トランザクションのローカル部分のリカバリを試みます。
RECOは、障害を起こしたトランザクションに関係している他のノードに対して、既存の接続を使用するか、または新しい接続を確立できます。接続が確立されると、RECOはすべてのインダウト・トランザクションを自動的に解決します。各データベースのペンディング・トランザクション表内にインダウト・トランザクションに対応している行があれば、自動的に削除されます。
ENABLE
/DISABLE DISTRIBUTED RECOVERY
オプションを指定してALTER SYSTEM
文を使用すると、RECOを使用可能または使用禁止にできます。たとえば、RECOを一時的に使用禁止にして2フェーズ・コミットの障害を強制的に発生させ、インダウト・トランザクションを手動で解決できます。
ALTER SYSTEM DISABLE DISTRIBUTED RECOVERY;
一方、次の文はRECOを使用可能にし、インダウト・トランザクションが自動的に解決されるようにします。
ALTER SYSTEM ENABLE DISTRIBUTED RECOVERY;
Oracle Databaseの分散読込み一貫性の実装には重要な制限事項があります。問題の原因は、各システムには独自のSCNがあり、データベースの内部的なタイムスタンプとして表示できることです。Oracle Databaseサーバーは、SCNを使用して、どのバージョンのデータが問合せから返されるかを判断します。
分散トランザクションのSCNは、各リモートSQL文の最後、および各トランザクションの最初と最後に同期化されます。2つのノード間の通信量が多く、特に分散更新がある場合には、この同期化が頻繁に実行されます。しかし、分散システムのSCNの絶対的な同期を保つための実用的な手段は存在しません。つまり、あるノードのSCNが別のノードのSCNと比べて幾分古くなるというような状況が常に存在します。
このようなSCNの食い違いから、実行した問合せがわずかに古いスナップショットを使用する可能性があり、その問合せ結果には、リモート・データベースに対する最新の変更が含まれていません。そのため、問合せを実行したときに、読込み一貫性に従ってデータが取得されているにもかからわず、そのデータが古い場合があります。そのような問合せによって取得したデータはすべて古いSCNに基づいているため、ローカルに実行した更新トランザクションによってリモート・ノードの2つの表が更新された場合、次回のリモート・アクセスで両方の表から選択したデータには、更新前のデータが含まれることになります。
SCNが食い違っているために起こりうる結果の1つとして、SELECT
文が2つ連続している場合に、それら2つの文の間でDMLをまったく実行していなくても各文で異なるデータが取得されることがあります。たとえば、UPDATE文を発行して、リモート・データベースで更新をコミットしたとします。このリモート表に基づくビューに対してSELECT
文を発行すると、ビューには更新された行が表示されません。次にSELECT
文を発行するときは、更新された行が表示されます。
次の手法を使用すると、問合せの直前に2つのシステムのSCNが必ず同期化されます。
SCNはリモート問合せの最後に同期化されるので、各リモート問合せの前に、同じサイトでSELECT * FROM DUAL@REMOTE
というようなダミーのリモート問合せを実行します。
SCNはすべてのリモート・トランザクションの最初に同期化されるので、リモート問合せを発行する前に、現行トランザクションをコミットまたはロールバックします。