Amazon DynamoDB Transactions: 仕組み - Amazon DynamoDB

Amazon DynamoDB Transactions: 仕組み

Amazon DynamoDB Transactions を使用すれば、複数のアクションをまとめてグループ化し、1 つのオールオアナッシングの TransactWriteItems または TransactGetItems オペレーションとして送信できます。以下のセクションでは、API オペレーション、容量管理、ベストプラクティス、DynamoDB でのトランザクション操作の使用に関する他の詳細について説明します。

TransactWriteItems API

TransactWriteItems は、最大 100 の書き込みアクションを 1 つのオールオアナッシングオペレーションにグループ化する、同期的でべき等な書き込みオペレーションです。これらのアクションは、同じ AWS アカウントおよび同じリージョン内の 1 つ以上の DynamoDB テーブルにある最大 100 個の異なる項目をターゲットにすることができます。トランザクション内のアイテムの合計サイズは 4 MB を超えることはできません。すべて成功するかどれも成功しないかのどちらとなるように、アトミックに実行されます。

注記
  • TransactWriteItems オペレーションは、含まれるすべてのアクションを正常に完了する必要があり、そうでない場合は変更がまったく行われないという点で BatchWriteItem オペレーションとは異なります。BatchWriteItem オペレーションでは、バッチ内の一部のアクションのみ成功し、他のアクションは成功しないことがあり得ます。

  • インデックスを使用してトランザクションを実行することはできません。

同じトランザクション内の複数のオペレーションが同じ項目をターゲットとすることはできません。たとえば、同じトランザクション内で同じ項目に対して ConditionCheck を実行し、Update アクションも実行することはできません。

以下のタイプのアクションをトランザクションに追加できます。

  • Put — PutItem オペレーションを開始し、条件付きで、または条件をまったく指定せずに、新しい項目を作成するか、古い項目を新しい項目に置き換えます。

  • Update — UpdateItem オペレーションを開始し、既存の項目の属性を編集するか、まだ存在しない場合は新しい項目をテーブルに追加します。条件付きまたは条件なしで既存の項目で属性を追加、削除、更新するには、このアクションを使用します。

  • Delete — DeleteItem オペレーションを開始し、プライマリキーにより識別される 1 つの項目をテーブルで削除します。

  • ConditionCheck — 項目が存在することを確認するか、項目の特定の属性の条件を確認します。

トランザクションが完了すると、そのトランザクションによって加えられた変更は、グローバルセカンダリインデックス (GSI)、ストリーム、バックアップに反映されます。反映は、即座に実行されないため、反映中の時点でテーブルがバックアップから復元されたり (RestoreTableFromBackup)、特定時点へエクスポートしたり (ExportTableToPointInTime) する場合、最近のトランザクション中に行われた変更の一部のみが含まれる可能性があります。

冪等性

TransactWriteItems 呼び出しを行ってリクエストが冪等であることを確認する場合、オプションでクライアントトークンを含めることができます。トランザクションを冪等にすると、接続のタイムアウトや他の接続問題に伴って同じオペレーションが複数回送信された場合に、アプリケーションエラーを防ぐことができます。

元の TransactWriteItems 呼び出しが成功した場合、同じクライアントトークンを持つ以降の TransactWriteItems 呼び出しは変更なしで正常に返ります。ReturnConsumedCapacity パラメータが設定されている場合、最初の TransactWriteItems 呼び出しは変更時に消費された書き込みキャパシティーユニットの数を返します。同じクライアントトークンを持つ以降の TransactWriteItems 呼び出しは、項目の読み取り時に消費された読み取りキャパシティユニットの数を返します。

冪等性について重要な点
  • クライアントトークンは、それを使用するリクエストが完了してから 10 分間有効です。10 分後、同じクライアントトークンを使用するリクエストは新しいリクエストとして扱われます。10 分が経過してから、同じリクエストに同じクライアントトークンを再利用しないでください。

  • 10 分間のべき等性期間内に同じクライアントトークンを使用してリクエストを繰り返すとき、他の一部のリクエストパラメータを変更した場合、DynamoDB は IdempotentParameterMismatch 例外を返します。

書き込みのエラー処理

以下の条件下では、書き込みトランザクションが成功しません。

  • いずれかの条件式の条件が満たされていない場合。

  • 同じ TransactWriteItems オペレーション内の複数のアクションが同じ項目をターゲットとしているために、トランザクション検証エラーが発生した場合。

  • TransactWriteItems リクエストが、TransactWriteItems リクエスト内の 1 つ以上の項目に対する継続中の TransactWriteItems オペレーションと競合する場合。この場合、リクエストは TransactionCanceledException で失敗します。

  • トランザクションを完了するプロビジョンドキャパシティーが足りない場合。

  • 項目サイズが大きくなりすぎる (400 KB 超)、ローカルセカンダリインデックス (LSI) が大きくなりすぎる、またはトランザクションにより変更が加えられたために同様の検証エラーが発生した場合。

  • 無効なデータ形式などのユーザーエラーがある場合。

TransactWriteItems オペレーションとの競合がどのように処理されるかについて詳しくは、「DynamoDB でのトランザクション競合の処理」を参照してください。

TransactGetItems API

TransactGetItems は、最大 100 個の Get アクションをまとめてグループ化する同期読み取りオペレーションです。これらのアクションは、同じ AWS アカウントおよびリージョン内の 1 つ以上の DynamoDB テーブルにある最大 100 個の異なる項目をターゲットにすることができます。トランザクション内の項目の合計サイズは 4 MB を超えることはできません。

Get アクションは、すべて成功するかすべて失敗するかのどちらとなるように、アトミックに実行されます。

  • Get — GetItem オペレーションを開始し、指定されたプライマリキーを持つ項目の属性のセットを取得します。一致する項目が見つからない場合、Get はデータを返しません。

読み込みのエラー処理

以下の条件下では、読み取りトランザクションが成功しません。

  • TransactGetItems リクエストが、TransactWriteItems リクエスト内の 1 つ以上の項目に対する継続中の TransactGetItems オペレーションと競合する場合。この場合、リクエストは TransactionCanceledException で失敗します。

  • トランザクションを完了するプロビジョンドキャパシティーが足りない場合。

  • 無効なデータ形式などのユーザーエラーがある場合。

TransactGetItems オペレーションとの競合がどのように処理されるかについて詳しくは、「DynamoDB でのトランザクション競合の処理」を参照してください。

DynamoDB トランザクションの分離レベル

トランザクションオペレーション (TransactWriteItems または TransactGetItems) と他のオペレーションの分離レベルは、次のとおりです。

SERIALIZABLE

直列化可能分離レベルでは、複数の同時オペレーションの結果は、前のオペレーションが完了するまでオペレーションが開始されない場合と同じになります。

以下のタイプのオペレーション間には、直列化可能分離があります。

  • トランザクションオペレーションと標準書き込みオペレーション (PutItemUpdateItem、または DeleteItem) の間。

  • トランザクションオペレーションと標準読み取りオペレーション (GetItem) の間。

  • TransactWriteItems オペレーションと TransactGetItems オペレーションの間。

トランザクションオペレーション間と BatchWriteItem オペレーション内の個々の標準書き込み間には直列化可能分離がありますが、トランザクションとユニットとしての BatchWriteItem オペレーションの間には直列化可能分離はありません。

同様に、トランザクションオペレーションと GetItems オペレーションの個別の BatchGetItem 間の分離レベルは直列化可能です。ただし、トランザクションとユニットとしての BatchGetItem オペレーション間の分離レベルはコミット済み読み取りです。

単一の GetItem リクエストは、TransactWriteItems リクエストの前または後に行う 2 つの方法のいずれかで、TransactWriteItems リクエストに関してシリアル化することができます。同時実行 TransactWriteItems リクエストのキーに対する複数の GetItem リクエストは、任意の順序で実行できるため、結果は読み込みがコミットされます。

たとえば、項目 A と項目 B の GetItem リクエストが、項目 A と項目 B の両方を変更する TransactWriteItems リクエストと同時に実行される場合、次の 4 つの可能性があります。

  • 両方の GetItem リクエストは、TransactWriteItems リクエストの前に実行されます。

  • 両方の GetItem リクエストは、TransactWriteItems リクエストの後に実行されます。

  • 項目 A の GetItem リクエストは、TransactWriteItems リクエストの前に実行されます。項目 B の場合、GetItemTransactWriteItems の後に実行されます。

  • 項目 B の GetItem リクエストは、TransactWriteItems リクエストの前に実行されます。項目 A の場合、GetItemTransactWriteItems の後に実行されます。

複数の GetItem リクエストにシリアル化可能な分離レベルが望ましい場合は、TransactGetItems を使用してください。

処理中に同じトランザクション書き込みリクエストの一部であった複数の項目に対して非トランザクション読み取りが行われた場合、一部の項目の新しい状態と他の項目の古い状態を読み取ることができる可能性があります。トランザクション書き込みリクエストに含まれていたすべての項目の新しい状態を読み取ることができるのは、トランザクション書き込みの応答が成功した場合のみです。

コミット済み読み取り

コミット済み読み取り分離により、読み取りオペレーションは常に項目のコミット済み値を返します。つまり、読み取りによって、最終的に成功しなかったトランザクション書き込みの状態を表すビューが項目に表示されることはありません。コミット済み読み取り分離では、読み取りオペレーションの直後に項目の変更が防止されません。

分離レベルは、トランザクションオペレーションと、複数の標準読み取り (BatchGetItemQuery、または Scan) が関係する読み取りオペレーションの間ではコミット済み読み取りです。トランザクション書き込みにより BatchGetItemQuery、または Scan オペレーションの途中で項目が更新された場合、その後の読み取りオペレーションの部分では、新しくコミットされた値 (ConsistentRead) を使用) か、場合によってはそれ以前のコミット済み値 (結果整合性のある読み込み) を返します。

オペレーションの概要

以下の表は、トランザクションオペレーション (TransactWriteItems または TransactGetItems) と他のオペレーションの間の分離レベルをまとめたものです。

オペレーション 分離レベル

DeleteItem

直列化可能

PutItem

直列化可能

UpdateItem

直列化可能

GetItem

直列化可能

BatchGetItem

コミット済み読み取り*

BatchWriteItem

直列化不可*

Query

コミット済み読み取り

Scan

コミット済み読み取り

他のトランザクションオペレーション

直列化可能

アスタリスク (*) が付いたレベルは、ユニットとしてオペレーションに適用されます。ただし、これらのオペレーション内の個々のアクションの分離レベルは直列化可能です。

DynamoDB でのトランザクション競合の処理

トランザクション競合は、トランザクション内の項目に対する項目レベルの同時リクエスト中に発生する場合があります。トランザクション競合は、次のシナリオで発生する場合があります。

  • 項目に対する PutItemUpdateItem、または DeleteItem リクエストが、同じ項目を含む継続中の TransactWriteItems リクエストと競合する。

  • TransactWriteItems リクエスト内の項目が、継続中の別の TransactWriteItems リクエストの一部である。

  • TransactGetItems リクエスト内の項目が、継続中の TransactWriteItemsBatchWriteItemPutItemUpdateItem、または DeleteItem リクエストの一部である。

注記
  • PutItemUpdateItem、または DeleteItem リクエストが拒否された場合、リクエストは TransactionConflictException で失敗します。

  • TransactWriteItems または TransactGetItems 内の項目レベルのリクエストが拒否された場合、リクエストは TransactionCanceledException で失敗します。そのリクエストが失敗した場合、AWS SDK はリクエストを再試行しません。

    AWS SDK for Java を使用している場合、例外には TransactItems リクエストパラメータの項目リスト通りに順序付けられた CancellationReasons のリストが含まれます。他の言語の場合、リストの文字列表現が例外のエラーメッセージに含まれます。

  • 継続中の TransactWriteItems オペレーションまたは TransactGetItems オペレーションが同時 GetItem リクエストと競合している場合、両方のオペレーションが成功する可能性があります。

TransactionConflict CloudWatch メトリクスは、項目レベルのリクエストが失敗するたびに増分されます。

DynamoDB アクセラレーター (DAX) でのトランザクション API の使用

TransactWriteItemsTransactGetItems が、どちらも DynamoDB と同じ分離レベルで DynamoDB アクセラレーター (DAX) でサポートされています。

TransactWriteItems は DAX を介して書き込みます。DAX は DynamoDB に TransactWriteItems コールを渡し、応答を返します。書き込み後にキャッシュにデータを追加するために、DAX は、TransactWriteItems オペレーション内の各項目に対してバックグラウンドで TransactGetItems をコールします。これにより、追加の読み込み容量単位が消費されます。(詳しくは、トランザクションの容量管理 を参照してください)。この機能により、アプリケーションロジックをシンプルに保ち、トランザクション処理と非トランザクション処理の両方に DAX を使用できます。

TransactGetItems コールは、項目がローカルにキャッシュされることなく DAX を通過します。これは、DAX の強い整合性のある読み込み API と同じです。

トランザクションの容量管理

DynamoDB テーブルのトランザクションを有効にするために、追加コストはかかりません。料金の支払いは、トランザクションの一部である読み込みまたは書き込みに対してのみ行われます。DynamoDB は、トランザクション内の各項目の基になっている 2 つの読み込みまたは書き込みを実行します。1 つはトランザクションの準備用で、もう 1 つはトランザクションのコミット用です。基になっている 2 つの読み込み/書き込みオペレーションは、Amazon CloudWatch メトリクスに表示されます。

容量をテーブルにプロビジョニングするとき、トランザクション API により要求される追加の読み取りと書き込みを計画してください。たとえば、アプリケーションが 1 秒あたり 1 件のトランザクションを実行し、各トランザクションは 500 バイトの項目を 3 個テーブルに書き込むとします。各項目には、2 つの書き込みキャパシティーユニット (WCU) が必要です。1 つはトランザクションの準備用で、もう 1 つはトランザクションのコミット用です。したがって、テーブルには WCU を 6 個プロビジョニングする必要があります。

前の例で DynamoDB アクセラレーター (DAX) を使用していた場合、TransactWriteItems のコールで項目ごとに 2 つの読み込み容量単位 (RCU) も使用します。したがって、テーブルには追加の RCU を 6 個プロビジョニングする必要があります。

同様に、アプリケーションが 1 秒あたり 1 件の読み込みトランザクションを実行し、各トランザクションは 500 バイトの項目を 3 個テーブルで読み取る場合、読み込み容量単位 (RCU) を 6 個テーブルにプロビジョンする必要があります。各項目を読み取るには、2 つの RCU が必要です。1 つはトランザクションの準備用で、もう 1 つはトランザクションのコミット用です。

さらに、SDK のデフォルトの動作は、TransactionInProgressException 例外が発生した場合にトランザクションを再試行します。これらの再試行で消費される追加の読み込みキャパシティーユニット (RCU) を計画してください。同じことは、ClientRequestToken を使用して独自のコードでトランザクションを再試行しようとする場合に当てはまります。

トランザクションのベストプラクティス

DynamoDB トランザクションの使用時に推奨される以下の手法を検討してください。

  • テーブルで自動スケーリングを有効にするか、トランザクションの項目ごとに 2 つの読み取りまたは書き込みオペレーションを実行するのに十分なスループット容量をプロビジョニングしたことを確認します。

  • AWS によって提供された SDK を使用していない場合、TransactWriteItems 呼び出しを行うときに ClientRequestToken 属性を含め、リクエストがべき等となるようにします。

  • 必要でない場合は、トランザクションにオペレーションをまとめてグループ化しないでください。たとえば、10 個のオペレーションを持つ 1 つのトランザクションを、アプリケーションの正確性を低下させずに複数のトランザクションに分割できる場合、トランザクションを分割することをお勧めします。トランザクションをシンプルにするとスループットが向上し、成功する可能性が高まります。

  • 同じ項目を同時に更新する複数のトランザクションによって、トランザクションをキャンセルする競合が発生する可能性があります。そのような競合を最小限に抑えるため、データモデリングには以下の DynamoDB のベストプラクティスをお勧めします。

  • 属性のセットが 1 つのトランザクションの一部として複数の項目間で頻繁に更新される場合、属性を 1 つの項目にグループ化し、トランザクションのスコープを減らすことを検討してください。

  • データを大量に取り込むためにトランザクションを使用しないでください。一括書き込みには、BatchWriteItem の使用をお勧めします。

グローバルテーブルでのトランザクション API の使用

DynamoDB トランザクションに含まれる操作は、そのトランザクションが最初に実行されたリージョンでのみトランザクション可能であることが保証されます。トランザクション内で適用された変更がリージョン間でグローバルテーブルのレプリカにレプリケートされても、トランザクション性は保持されません。

DynamoDB トランザクションと AWSLabs トランザクションクライアントライブラリ

DynamoDB トランザクションには、AWSLabs トランザクションクライアントライブラリを置き換えるより費用対効率、堅牢性、パフォーマンスに優れた手段が用意されています。ネイティブのサーバー側トランザクション API を使用するようにアプリケーションを更新することをお勧めします。