TimesTen Scaleoutでは、分散トランザクションは2フェーズ・コミットのプロトコルによって処理されます。この章では、TimesTen Scaleoutが分散トランザクションを介してACID準拠のデータベースを保守する方法について説明します。
TimesTen Scaleoutで採用されている分散トランザクション処理アルゴリズムの理解に関連する用語は、次のとおりです。
参加者: 分散トランザクションから1つ以上のSQL文を実行する要素。データベース内のすべての要素がすべてのトランザクションに参加するわけではありません。要素は、トランザクションの1つ以上の操作でその要素に格納されているデータにアクセスする必要がある場合にのみ、そのトランザクションの参加者になります。
ノート: 各要素には、専用の独立したチェックポイントおよびトランザクション・ログ・ファイルのセットが保持されます。これらは、TimesTen Classicのデータベースのチェックポイントおよびトランザクション・ログ・ファイルと同様に動作します。詳細は、Oracle TimesTen In-Memory Databaseオペレーション・ガイドのチェックポイント処理およびトランザクション・ロギングを参照してください。 |
トランザクション・マネージャ: データベースに接続され、トランザクションを開始するアプリケーション(クライアント/サーバー・アプリケーションの場合はTimesTen Server)のスレッド。トランザクション・マネージャは、すべての参加者とトランザクション操作を調整します。
コミットの準備ログ・レコード: 2フェーズ・コミットのプロトコルの準備フェーズ中にデータベースのトランザクション・ログに書き込まれるログ・レコードのタイプ。これには、トランザクションのコミットの決定が含まれます。
永続ログ・レコード: 参加者がトランザクション・ログと同期してコミットの準備またはコミット・ログ・レコードに書き込みます。非永続ログ・レコードは、参加者によって非同期に書き込まれます。
分散トランザクション: 2つ以上の参加者があるトランザクション。
単一要素トランザクション: 参加者が1つのみのトランザクション。単一要素トランザクションでは、2フェーズ・コミットのプロトコルを使用しません。単一要素トランザクションは、K-safetyが1
に設定されているグリッド内でのみ使用できます。
インダウト・トランザクション: 参加者がコミットの準備ログ・レコードを書き込んだが、コミット・ログ・レコードがトランザクション・ログに存在していないトランザクション。トランザクション・マネージャがコミットの準備ログ・レコードをトランザクション・ログ書き込んだ場合は、既知のミットの決定があることを意味し、トランザクションはインダウトではありません。
この章には次のトピックが含まれます:
アプリケーションは、データベースの1つの要素に接続することによって、TimesTen Scaleoutのデータベースに接続します。接続によって実行される各トランザクションには、トランザクション・マネージャが必要です。クライアント/サーバー・アプリケーションの場合、トランザクション・マネージャは、アプリケーションのプロキシとして機能しているTimesTen Scaleoutサーバーのスレッドです。ダイレクト・モードのアプリケーションの場合、トランザクション・マネージャは、TimesTen Scaleoutに接続するアプリケーションのスレッドです。トランザクション・マネージャは、要素(参加者)での文の実行を調整します。具体的には次を行います。
アプリケーションがコミットまたはロールバックを発行すると、トランザクション・マネージャは、すべての参加者が2フェーズ・コミットのプロトコルからのコミットまたはロールバックの決定に基づく一貫性のあるデータを持っていることを確認します。
制約違反などのエラーが参加者に返された場合、トランザクション・マネージャは、レスポンスを調整します。トランザクション・マネージャは、TimesTen Scaleoutがユーザーに適切なエラー・メッセージを返し、すべての参加者が割り当てられたリソースを解放することを確認します。
参加者に障害が発生した場合、トランザクション・マネージャは、障害が発生した参加者が一貫性のある状態にリストアするためにリカバリ時に使用する状態を作成します。
トランザクション・マネージャが存在する参加者に障害が発生した場合、参加者は、準備フェーズを完了したが、コミットの決定を受信しておらず、トランザクション・マネージャにアクセスできなくなっている場合、トランザクションをインダウトとして分類します。
参加者は文の実行を完了すると、トランザクション・マネージャにメッセージを送信します。メッセージには、影響を受けた行数に関する情報が含まれます。メッセージの指定内容とその処理は、次のとおりです。
参加者がINSERT
、UPDATE
、DELETE
などの操作を使用して影響を受ける行を変更した場合、トランザクション・マネージャは参加者に書込み参加者としてフラグを設定します。
参加者が行を変更しなかった場合、トランザクション・マネージャは参加者に読取り参加者としてフラグを設定します。
参加者の読込みまたは書込みの状態は、トランザクション・マネージャがコミット操作を処理する方法に影響します。
すべての参加者が読取り参加者である場合、トランザクション・マネージャは、準備フェーズを経由せずにコミットを処理します。つまり、読取り参加者は他の参加者からの合意を必要とすることなくコミット操作を実行します。
1つ以上の書込み参加者がある場合、トランザクション・マネージャはコミットを2フェーズの操作として処理します。
トランザクションの永続性を制御するには、Durability
属性を使用します。この属性は、トランザクションが永続コミットの準備ログ・レコードを作成するかどうかを定義します。この属性の設定にかかわらず、DDL文を含むトランザクションは永続コミットの準備ログ・レコードをコミットします。Durability
属性では、次の2つの値がサポートされます。
Durability
属性を1
に設定すると、参加者が分散トランザクションの永続コミットの準備ログ・レコードおよび非永続コミット・ログ・レコードを書き込みます。Durability
属性を1
に設定すると、コミットされたトランザクションが失敗した場合にリカバリ可能になります。これは、K-safetyが1
に設定されている場合のDurability
属性のデフォルト設定です。
Durability
属性の詳細は、Oracle TimesTen In-Memory DatabaseリファレンスのDurabilityを参照してください。
Durability
属性を0
に設定すると、参加者が分散トランザクションの非永続コミットの準備ログ・レコードおよびコミット・ログ・レコードを書き込みます。永続性を確保するために、TimesTen Scaleoutには、通常、Durability
属性が0
に設定されているデータベース専用の次の新機能が用意されています。
エポック・トランザクションは、データベースのすべての要素間でグローバルに一貫性のあるポイントをマークする永続コミット・ログ・レコードを作成する分散トランザクションです。エポック・トランザクションは、データベースのすべての要素に永続的にコミットされます。エポック・トランザクションにより、エポック・トランザクションのタイムスタンプまでデータベースに一貫性があることが確認されます。つまり、エポック・トランザクションによって、すでにコミット・フェーズにあるトランザクションがリカバリ可能となります。
TimesTen Scaleoutでは、障害が発生した要素のレプリカ・セットを含むトランザクションの永続コミットの準備ログ・レコードを、障害が発生した要素がリカバリするまで書き込むため、K-safetyが2
に設定されているグリッドのトランザクションおよびDurability
属性が0
に設定されているデータベースは、通常、永続的です。レプリカ・セットの両方の要素で同時に障害が発生した場合にのみ、トランザクションが非永続になります。ただし、TimesTen Scaleoutでは、トランザクションをエポック・トランザクションに昇格できます。エポック・トランザクションのエポック・コミット・ログ・レコードでマークされた一貫性のある時点にデータベースをリカバリできるため、エポック・トランザクションとその前にコミットされたすべてのトランザクションには、重大な障害に対するより高いリジリエンスがあります。
ノート:
|
トランザクションを昇格する前に、エポック・トランザクションは、コミットの準備およびコミット・フェーズの永続ログ・レコードを作成し、トランザクションのエポック・トランザクションへの昇格の前には参加者ではなかったものを含むデータベースのすべての要素が関連するため、エポック・トランザクションのコミットは通常のトランザクションのコミットよりも負荷が高いことを考慮してください。
次の組込みプロシージャおよびシステム・ビューを使用して、エポック・トランザクションを昇格および管理します。
ttEpochCreate
組込みプロシージャは、読取り専用トランザクションを含むトランザクションをエポック・トランザクションに昇格します。
ttDurableCommit
組込みプロシージャは、書込みトランザクションをエポック・トランザクションに昇格します。
SYS.V$EPOCH_SESSION
システム・ビューには、接続が最後から2番目のチェックポイント処理以降に作成された最新のエポック・トランザクションのLamportタイムスタンプが格納されます。
例6-1 トランザクションのエポック・トランザクションへの昇格
次の例では、書込みトランザクションのエポック・トランザクションへの昇格を示し、検証します。
Command> autocommit OFF; Command> INSERT INTO transactions VALUES (txn_seq.NEXTVAL, 189, SYSDATE, NULL, 'A', 5.49); Command> SELECT epoch FROM sys.v$epoch_session; < 1023.1 > 1 row found. Command> CALL ttEpochCreate(); Command> COMMIT; Command> SELECT epoch FROM sys.v$epoch_session; < 1024.1 > 1 row found.
ttEpochCreate
またはttDurableCommit
組込みプロシージャの詳細は、Oracle TimesTen In-Memory DatabaseリファレンスのそれぞれttEpochCreateまたはttDurableCommitを参照してください。
SYS.V$EPOCH_SESSION
システム・ビューの詳細は、Oracle TimesTen In-Memory Databaseシステム表およびビュー・リファレンスのSYS.V$EPOCH_SESSIONを参照してください。
各エポック・コミット・ログ・レコードは、各要素の特定のチェックポイント・ファイルに関連付けられます。要素に予期しない障害が発生した場合、リカバリ・プロセスでは、最新のエポック・コミット・ログ・レコードに関連付けられている各要素のチェックポイント・ファイルを使用する必要があります。このチェックポイントは、必ずしもその要素の最新のチェックポイントではありません。
最初の接続属性EpochInterval
を使用して、指定された間隔で定期エポック・トランザクションを生成するようにデータベースを構成できます。すべてのチェックポイント処理を実行するエポック・トランザクションが少なくとも1つはあるように、EpochInterval
属性に設定された値は、最初の接続属性CkptFrequency
に設定されている値の半分未満である必要があります。CkptFrequency
属性を0より大きい値に設定し、EpochInterval
属性をCkptFrequency
属性に設定された値の半分よりも大きい値に設定すると、TimesTen Scaleoutは、EpochInterval
属性をCkptFrequency
属性に設定された値の半分に再調整します。
EpochInterval
またはCkptFrequency
属性の詳細は、Oracle TimesTen In-Memory DatabaseリファレンスのそれぞれEpochIntervalまたはCkptFrequencyを参照してください。
CreateEpochAtCommit
一般接続属性を使用して、エポック・トランザクションへの接続によってコミットされたすべての書込みトランザクションを昇格するように接続を構成できます。CreateEpochAtCommit
属性を1
に設定すると、接続時にコミットするすべてのトランザクションが、障害が発生した場合にリカバリ可能になります。ただし、エポック・トランザクションと同様に、コミット操作は、通常のトランザクションよりも負荷が高いため、重要な操作のみにCreateEpochAtCommit=1
を限定することをお薦めします。
ノート: DurableCommits 属性はTimesTen Classicのデータベースを対象としていますが、この属性は、TimesTen Scaleoutのデータベースで1 に設定されている場合、CreateEpochAtCommit 属性の動作をエミュレートします。詳細は、Oracle TimesTen In-Memory DatabaseリファレンスのDurableCommitsを参照してください。 |
表6-1に示すように、Durability
属性が0
に設定されている場合、トランザクション・マネージャと参加者は、CreateEpochAtCommit
属性の設定によって動作が異なります。
表6-1 CreateEpochAtCommitの設定に基づくコミットでの参加者の動作
CreateEpochAtCommit | コミット動作 |
---|---|
|
参加者は、分散トランザクションの非永続コミットの準備およびコミット・ログ・レコードを書き込みます。 |
|
すべてのトランザクションがエポック・トランザクションに昇格します。 |
Durability
およびCreateEpochAtCommit
属性の両方を0
に設定すると、最高のパフォーマンスが得られます。この場合は、ttEpochCreate
またはttDurableCommit
組込みプロシージャを呼び出して、重要なトランザクションの永続レコードがあることを確認します。
Durability
またはCreateEpochAtCommit
属性の詳細は、Oracle TimesTen In-Memory DatabaseリファレンスのそれぞれDurabilityまたはCreateEpochAtCommitを参照してください。ttEpochCreate
またはttDurableCommit
組込みプロシージャの詳細は、Oracle TimesTen In-Memory DatabaseリファレンスのそれぞれttEpochCreateまたはttDurableCommitを参照してください。
この項を読む前に、トランザクション・マネージャおよび永続性の設定で説明されている概念を理解していることを確認してください。
前述のとおり、分散トランザクションは2フェーズ・コミットのプロトコルに従います。TimesTen Scaleoutでは、次のように2フェーズ・コミットのプロトコルを実装します。
アプリケーションが、データベースへの接続を確立します。すべての接続は、データベースの特定の要素に関連付けられ、その接続から開始されるすべての分散トランザクションのトランザクション・マネージャとなります。
アプリケーションが、1つ以上のSQL文を実行します。トランザクション・マネージャは、すべての参加者に文を送信して実行します。SQL文の実行で返された結果に基づいて、トランザクション・マネージャは参加者のステータスを識別して更新します。
アプリケーションが、コミットを発行します。
トランザクション・マネージャが、すべての参加者に準備メッセージを送信します。このメッセージには、トランザクション・マネージャおよびすべての参加者のIDが含まれています。
準備メッセージを受信した各参加者が、次のいずれかの操作を実行します。
参加者が書込み参加者である場合は、情報を格納して、その後、トランザクションをコミットまたはロールバックするコミットの準備ログ・レコードを書き込みます。また、参加者は、読取り操作を防ぐために変更された行をロックします。
参加者が読取り参加者である場合は、トランザクションを読取り専用として識別します。
参加者が、コミット決定の投票によって、トランザクション・マネージャに準備レスポンスを送信します。
書込み参加者がコミットの準備ログ・レコードを書き込むことができた場合は、「Yes」のみを投票します。
ノート: Durability が1 に設定されている場合、参加者は永続コミットの準備ログ・レコードを書き込みます。 |
読取り参加者は、常に「Yes」を投票し、コミットの決定を待機しないでトランザクションをコミットします。この場合、コミット操作は、トランザクションに関連するすべてのロックおよび一時リソースの解放で構成されます。
トランザクション・マネージャは、トランザクションに参加するすべてのレプリカ・セット内の1つ以上の要素から準備レスポンスを受信すると、コミットの決定を含むコミットの準備ログ・レコードを書き込みます。トランザクション・マネージャでは、コミットの決定は表6-2に記載されたシナリオに基づきます。
トランザクション・マネージャが、すべての書込み参加者にコミットの決定とともにメッセージを送信します。
トランザクション・マネージャを含むすべての書込み参加者が、コミットの決定に基づいてトランザクションをコミットまたはロールバックします。
図6-1は、TimesTen Scaleoutでの分散トランザクションの2フェーズ・コミットのプロトコルの実装を示しています。
未処理の分散トランザクションのデータベースの操作に影響を与える可能性がある潜在的な障害には、複数のタイプがあります。表6-3は、これらの障害のタイプの概要を示し、TimesTen Scaleoutによる障害への対応について説明します。
表6-3 分散トランザクションの障害タイプ
障害 | アクション |
---|---|
トランザクション・マネージャに障害が発生します。 |
トランザクション・マネージャに障害が発生した(アプリケーションが終了したなど)場合は、そのインスタンスのメイン・デーモンが障害を捕捉し、サブデーモンに通知します。サブデーモンは、トランザクションの状態に応じて、すべての参加者にコミットまたはロールバック・メッセージを送信します。 |
トランザクション・マネージャのホストに障害が発生します。 |
トランザクション・マネージャのホストに障害が発生すると、デーモンおよびすべてのサブデーモンに障害が発生します。各参加者は、トランザクション・マネージャへのTCP接続が閉じられるか、またはタイムアウトになったときにこの障害を認識します。 参加者は、障害を認識すると、準備フェーズに到達していないトランザクションをロールバックします。参加者がすでにその準備レスポンスを送信した場合は、他の参加者にコミットの決定を依頼し、次のいずれかのアクションを実行します。
|
コミットの準備ログ・レコードを書き込む前に、参加しているレプリカ・セットのすべての要素に障害が発生します。 |
トランザクション・マネージャが、トランザクションのロールバックを決定します。 |
コミットの準備ログ・レコードの書込み後に、参加者に障害が発生します。 |
参加者は、リカバリ後に、他の参加者のいずれかによるコミットの決定をリクエストします。 |
参加者がビジー状態です。 |
トランザクション・マネージャは、参加者から準備レスポンスを受信するまで待機します。 |
TimesTen Classicでは、トランザクションが別のトランザクションによって保持されているリソースを待機する必要がある場合があります。リソースはロックで保護されている場合、トランザクションはロックが解放されるまで待機します。他のトランザクションがデータ・ロックとして示されていない外部イベントを待機している可能性があるため、デッドロック検出によって問題が解決されません。トランザクションが待機する原因となる可能性があるリソースは、次のとおりです。
セマフォ待機
ラッチ待機
I/Oイベント
参加者のないオープン・トランザクション
長時間実行されている操作
TimesTen Scaleoutでは、これらのケースがまだ該当し、さらに別のケースである可能性もあります。要素に障害が発生すると、その要素から開始されたすべてのトランザクションでは、トランザクション・マネージャが失われています。リモート参加者は、準備レスポンスの送信後にトランザクションのコミットの決定を受信しなかった場合、インダウトになったトランザクションをコミットまたはロールバックするのを待機する必要があります。また、準備レスポンスを送信した後、コミットの決定を受け取る前に参加者に障害が発生した場合、トランザクションは障害が発生した参加者のインダウト・トランザクションになります。
グローバル・トランザクションIDは、データベースのすべての要素にわたるトランザクションを一意に識別します。グローバル・トランザクションIDは、次のパラメータで構成されます。
トランザクション・マネージャの要素ID
トランザクション・マネージャの接続IDまたはローカル・トランザクションID
接続から発行されたトランザクションのカウンタ
TimesTen Scaleoutで未処理トランザクションのグローバル・トランザクションIDを取得する方法の詳細は、例6-2を参照してください。
例6-2 グローバル・トランザクションIDの取得
この例では、トランザクションを発行する接続内からグローバル・トランザクションIDを取得する方法を示しています。SYS.V$XACT_ID
システム・ビューには、トランザクションのグローバル・トランザクションIDを作成するために必要なすべてのパラメータが格納されます。
Command> autocommit 0; Command> INSERT INTO transactions VALUES (txn_seq.NEXTVAL, 342, SYSDATE, NULL, 'A', 8.33); 1 row inserted. Command> SELECT elementId, xactId, counter FROM sys.v$xact_id; < 3, 1, 148 > 1 row found.
SYS.V$XACT_ID
システム・ビューの詳細は、Oracle TimesTen In-Memory Databaseシステム表およびビュー・リファレンスのSYS.V$XACT_IDを参照してください。
TimesTen Scaleoutは、要素のリカバリ中にインダウト・トランザクションを自動的に解決します。トランザクションのコミットの準備ログ・レコードには、他の参加者に関する情報が含まれます。インダウト・トランザクションを解決するために、リカバリ要素は、コミットの準備ログ・レコードにリストされているいずれかの参加者からのコミットの決定をリクエストします。
トランザクション・マネージャに障害が発生した場合、TimesTen Scaleoutは、各書込みレプリカ・セットの1つの参加者が使用可能である場合はインダウト・トランザクションを解決できます。ただし、どの参加者にもコミットの決定がなく、すべての書込みレプリカ・セットが使用可能というわけではない場合、TimesTen Scaleoutは、インダウト・トランザクションを解決できません。TimesTen Scaleoutがインダウト・トランザクションを解決できなかった場合は、ttXactAdmin
ユーティリティを使用して、トランザクションのコミットまたはロールバックを強制します。
重要: ほとんどの場合、未解決のインダウト・トランザクションは常にロールバックする必要があります。ただし、トランザクションを外部からコミットする場合は、一貫性のあるデータベースを保証するために、使用不可の参加レプリカを除去する必要があります。レプリカ・セットの除去は、レプリカ・セットに格納されたすべてのデータが失われることを意味します。レプリカ・セットの除去の詳細は、レプリカ・セット全体が停止するか障害が発生した場合のデータの使用不可を参照してください。 |
ttXactAdmin
ユーティリティを使用して、すべての未処理トランザクションのstate
を確認できます。例6-3を参照してください。トランザクションのstate
がin-doubt
である場合は、同じユーティリティを使用してトランザクションを外部からコミットまたはロールバックできます。例6-4または例6-5をそれぞれ参照してください。
例6-3 すべての未処理トランザクションの状態の確認
この例は、コマンドを実行しているデータ・インスタンスの要素が参加者であるすべての未処理トランザクションのステータスを取得する方法を示しています。ttXactAdmin
ユーティリティは、コマンドを実行しているデータ・インスタンスの要素に関連する情報のみを取得します。
% ttXactAdmin -connStr "DSN=database1" 2016-12-14 11:00:36.995 /disk1/databases/database1 TimesTen Release 18.1.4.1.0 ElementID 3 Program File Name: _ttIsql XactID PID Context State Loghold Last ID 3.1.148 26247 0x13b3ff0 Active -1.-1 [-1:2] Resource ResourceID Mode SqlCmdID Name Database 0x01312d0001312d00 IX 0 HashedKey ffffffffe5a341d5 SF 284478280 PAT.ACCOUNTS Table 2367304 IRC 284478280 PAT.ACCOUNTS EndScan AAAVVUAAAA9AAAAGjO En 284478280 PAT.TRANSACTIONS Table 2367320 IRC 284478280 PAT.TRANSACTIONS Begin Time: 10:59:21.695
例6-4 インダウト・トランザクションのコミット
この例では、ttXactAdmin
ユーティリティを使用して、トランザクション3.1.148をコミットします。このコマンドは、トランザクション・マネージャが停止しており、そのレプリカ・セットがデータベースから除去された場合にのみ正常に実行されます。障害が発生したレプリカ・セットを除去する時期と方法の詳細は、停止しているレプリカ・セットからのリカバリを参照してください。
% ttXactAdmin -connStr "DSN=database1" -xactIdCommit 3.1.148
例6-5 インダウト・トランザクションのロールバック
この例では、ttXactAdmin
ユーティリティを使用して、トランザクション3.1.148をロールバックします。
% ttXactAdmin -connStr "DSN=database1" -xactIdRollback 3.1.148
ttXactAdmin
ユーティリティの詳細は、Oracle TimesTen In-Memory DatabaseリファレンスのttXactAdminを参照してください。