グローバルテーブルによる書き込みモード
グローバルテーブルは、テーブルレベルでは常にアクティブ/アクティブです。ただし、書き込みリクエストのルーティング方法を制御して、アクティブ/パッシブとして扱うこともできます。例えば、書き込みが競合しないように、書き込みリクエストを単一のリージョンにルーティングすることを決定する場合があります。
マネージドの書き込みパターンは、主に以下の 3 つに分類されます。
任意のリージョンへの書き込みモード (プライマリなし)
1 つのリージョンへの書き込みモード (単一プライマリ)
自分のリージョンへの書き込みモード (混合プライマリ)
どの書き込みパターンがユースケースに適しているかを検討する必要があります。この選択は、リクエストのルーティング、リージョンの退避、ディザスタリカバリの処理方法に影響します。全体的なベストプラクティスは、アプリケーションの書き込みモードによって異なる場合があります。
任意のリージョンへの書き込みモード (プライマリなし)
任意のリージョンへの書き込みモードは、完全にアクティブ/アクティブであり、書き込みが発生する場所に制限はありません。任意のリージョンにいつでも書き込むことができます。これは最も単純なモードです。このモードは、一部のタイプのアプリケーションでのみ使用できます。すべてのライターが冪等であるため、安全に繰り返し実行可能であり、リージョンをまたいでの同時または繰り返しの書き込みオペレーションが競合しないという場合に適しています。例えば、ユーザーが連絡先データを更新する場合などに使用できます。このモードは、冪等である特殊なケースとして、確定的なプライマリキーにおけるすべての書き込みが一意の挿入であるという、追加専用のデータセットにも適しています。最後に、このモードは、書き込みの競合リスクを許容できる場合に適しています。
![クライアントが任意のリージョンに書き込む仕組みを示す図。](images/gt-client-read-write-to-any-region.png)
任意のリージョンへの書き込みモードは、実装が最も簡単なアーキテクチャです。いつでも任意のリージョンを書き込み先にすることができるため、ルーティングが容易になります。最近の書き込みを任意のセカンダリリージョンに何度でもリプレイできるため、フェイルオーバーが容易になります。可能な限り、この書き込みモード向けの設計を行うようにします。
例えば、ビデオストリーミングサービスでは、ブックマーク、レビュー、視聴ステータスフラグなどの追跡にグローバルテーブルをよく使用します。これらのデプロイで任意のリージョンへの書き込みモードを使用できるのは、すべての書き込みが冪等で、項目の次の正しい値が現在の値に依存しない場合に限ります。これは、最新のタイムコードの新規設定、新しいレビューの割り当て、新しい視聴ステータスの設定など、ユーザーの新しいステータスを直接割り当ててユーザーを更新する場合に当てはまります。ユーザーの書き込みリクエストが複数の異なるリージョンにルーティングされた場合、最後の書き込みオペレーションが保持され、最後の割り当てに従ってグローバル状態が確定します。このモードでの読み取りオペレーションは、最新の ReplicationLatency
値の遅延後に、結果的に整合します。
別の例として、ある金融サービス会社では、システムの一部としてグローバルテーブルを使用し、各顧客のデビットカード購入の累計を管理して、その顧客のキャッシュバック特典を計算しています。新しいトランザクションは世界中から流入し、複数のリージョンに送られます。グローバルテーブルを利用しない現在の設計では、顧客ごとに 1 つの収支項目を使用しています。顧客のアクションに応じて残高が ADD 式で更新されます。ただし、新しい正しい値は現在の値によって異なるため、この式は冪等ではありません。つまり、複数の異なるリージョンで同じ残高に対してほぼ同時に 2 つの書き込みオペレーションが行われた場合、残高が同期しなくなります。
この同じ会社は、DynamoDB のグローバルテーブルを使用して慎重に再設計することで、任意のリージョンへの書き込みモードを実現できます。新しい設計では、「イベントストリーミング」モデル、つまり実質的には追加専用のワークフローを持つ台帳を採用できます。顧客のアクションごとに、その顧客用に管理されている項目コレクションに新しい項目が追加されます。項目コレクションは、プライマリキーを共有し、異なるソートキーを持つ項目のセットです。顧客のアクションを追加する各書き込みアクションは、冪等挿入であり、顧客 ID をパーティションキーとして使用し、トランザクション ID をソートキーとして使用します。この設計では、項目をプルしてからクライアント側で計算を行うために Query
が必要になり、残高の計算がより複雑になります。ただし、すべての書き込みが冪等になるため、ルーティングとフェイルオーバーが大幅に簡素化されるという利点があります。詳細については、「グローバルテーブルを使用したリクエストルーティング」を参照してください。
3 番目の例として、オンライン広告を掲載している企業があるとします。この企業は、任意のリージョンへの書き込みモードによる設計の簡素化を実現するには、低リスクのデータ損失は許容できると判断しました。広告を配信する際には、わずか数ミリ秒で十分なメタデータを取得してどの広告を表示するか決定し、広告インプレッションを記録して、ユーザーに同じ広告が繰り返し表示されないようにしています。グローバルテーブルを使用すると、世界中のエンドユーザーに対して低レイテンシーの読み取りと低レイテンシーの書き込みの両方を提供できます。ユーザーのすべての広告インプレッションを 1 つの項目内に記録し、それを成長するリストとすることができます。項目コレクションに追加する代わりに 1 つの項目を使用できます。これにより、各書き込みの一部として古い広告インプレッションを削除できるため、削除に料金を支払う必要がありません。この書き込みオペレーションは冪等ではないため、同じエンドユーザーが複数のリージョンからほぼ同時に配信された広告を見た場合、ある広告インプレッションの書き込みが他の広告インプレッションの書き込みを上書きする可能性があります。オンライン広告の場合、ユーザーが広告を繰り返し見るリスクがあるとしても、このシンプルで効率的な設計を採用する価値があります。
単一プライマリ (「1 つのリージョンへの書き込み」)
1 つのリージョンへの書き込みモードはアクティブ/パッシブで、すべてのテーブル書き込みを 1 つのアクティブリージョンにルーティングします。DynamoDB には 1 つのアクティブリージョンという概念がないことに注意してください。DynamoDB の外部のアプリケーションルーティングがこれを管理します。1 つのリージョンへの書き込みモードは、一度に 1 つのリージョンにのみ書き込むようにすることで、書き込みの競合を回避します。この書き込みモードは、条件式やトランザクションを使用する場合に役立ちます。条件式やトランザクションは、最新であることが明白なデータに適応しないと、意味がないためです。したがって、条件式とトランザクションを使用するには、すべての書き込みリクエストを最新のデータがある 1 つのリージョンに送信する必要があります。
結果整合性のある読み込みは、任意のレプリカリージョンに送信してレイテンシーを短縮できます。強力な整合性のある読み込みは、単一のプライマリリージョンに送信する必要があります。
![1 つのリージョンへの書き込みの仕組みを示す図。](images/gt-client-writes-one-region.png)
リージョンの障害に対応するために、アクティブなリージョンを変更してデータを処理することが必要になる場合があります。グローバルテーブルを使用したリージョンからの退避は、このユースケースの一例です。「フォローザサン」デプロイなどで、現在アクティブなリージョンを定期的に変更する場合もあります。これにより、アクティブなリージョンが最もアクティビティの多い地域の近くに配置され、読み取りと書き込みのレイテンシーが最小限に抑えられます。これには、リージョンを変更するコードパスを毎日呼び出すことで、ディザスタリカバリの前にコードパスが十分にテスト済みであることを確認できるという、副次的な利点もあります。
パッシブリージョンでは、DynamoDB を取り巻くインフラストラクチャをダウンスケールしたままにして、アクティブリージョンになったときにのみ構築を行う場合があります。パイロットライトとウォームスタンバイの設計の詳細については、「AWS でのディザスタリカバリ (DR) アーキテクチャ、パート III: パイロットライトとウォームスタンバイ
グローバルテーブルを活用して低レイテンシーのグローバル分散読み取りを行う場合は、1 つのリージョンへの書き込みモードを使用すると効果的です。例えば、大規模なソーシャルメディア会社には、数百万のユーザーと数十億の投稿があります。各ユーザーは、アカウント作成時に、自分の所在地と地理的に近いリージョンに割り当てられます。ユーザーのすべてのデータは、そのリージョンの非グローバルテーブルに格納されます。同社では、1 つのリージョンへの書き込みモードを使用し、別個のグローバルテーブルでユーザーのホームリージョンへのマッピングを保持しています。読み取り専用のコピーが世界中に保存されるため、レイテンシーを最小限に抑えながら、各ユーザーのデータを直接検索できます。更新はまれであり (ユーザーのホームリージョンを別のリージョンに移動する場合のみ)、必ず 1 つのリージョンを経由して書き込むため、書き込みの競合を回避できます。
別の例として、毎日のキャッシュバック計算を実装した金融サービス会社を考えてみましょう。同社は、残高の計算には任意のリージョンへの書き込みモードを使用していますが、実際のキャッシュバック支払いの追跡には 1 つのリージョンへの書き込みモードを使用しています。1 日に 10 ドル使うごとに 1 ペニーの報酬を顧客に提供するには、前日のすべてのトランザクションに対して Query
を実行して、支出総額を計算し、キャッシュバックを決定して新しいテーブルに書き込み、クエリした項目のセットを削除する必要があります。これを消費済みとしてマークし、単一の項目に置き換えて翌日の計算に使用する残額を格納します。この作業にはトランザクションが必要であるため、1 つのリージョンへの書き込みモードを使用すると、より効率的です。ワークロードが重複する可能性がない限り、アプリケーションは同じテーブルに対しても複数の書き込みモードを一緒に使用できます。
混合プライマリ (「自分のリージョンへの書き込み」)
自分のリージョンへの書き込みモードでは、データサブセット別に異なるリージョンに割り当て、ホームリージョンを介した項目への書き込みオペレーションのみを許可します。このモードはアクティブ/パッシブですが、項目に応じてアクティブリージョンを割り当てます。各リージョンは重複しない独自のデータセットのプライマリであり、適切なローカリティを確保するために書き込みを保護する必要があります。
このモードは 1 つのリージョンへの書き込みと似ていますが、各エンドユーザーに関連するデータを、そのユーザーに近いネットワークに配置できるため、書き込みのレイテンシーを短縮できる点が異なります。また、周囲のインフラストラクチャがリージョン間でより均等に分散され、すべてのリージョンでインフラストラクチャの一部が既にアクティブになっているため、フェイルオーバーシナリオ時にインフラストラクチャを構築する作業が少なくなります。
![クライアントが 1 つのリージョンで各項目に書き込む仕組みを示す図。](images/get-client-writes-each-item-single-region.png)
項目のホームリージョンは、さまざまな方法で決定できます。
固有: パーティションキーなど、データの一部の側面により、データがどのリージョンをホームとするかが明確になります。例えば、顧客とその顧客に関するすべてのデータには、顧客データ内で、特定のリージョンをホームとすることがマークされます。この手法については、「リージョンのピン留めを使用して Amazon DynamoDB グローバルテーブル内の項目のホームリージョンを設定する
」で説明しています。 ネゴシエート済み: 各データセットのホームリージョンは、割り当てを管理する別のグローバルサービスなど、何らかの外部的な方法でネゴシエート済みです。割り当てには有限の期間があり、その後は再ネゴシエーションの対象となります。
テーブル指向: レプリケートするグローバルテーブルを 1 つ作成するのではなく、レプリケートするリージョンの数だけグローバルテーブルを作成します。各テーブルの名前はホームリージョンを示します。標準オペレーションでは、すべてのデータがホームリージョンに書き込まれ、他のリージョンは読み取り専用のコピーを保持します。フェイルオーバー中、別のリージョンがそのテーブルの書き込みタスクを一時的に引き継ぎます。
例えば、ゲーム会社で働いているとしましょう。世界中のすべてのゲーマーに、低レイテンシーの読み取りと書き込みが必要です。各ゲーマーのホームは、最も近いリージョンに設定できます。このリージョンですべての読み取りと書き込みが行われるため、強力な整合性のある読み込みと書き込みが常に確保されます。ただし、ゲーマーが旅行したり、ホームリージョンが停止したりした場合は、データの完全なコピーが別のリージョンで利用できるようになります。したがって、必要に応じてゲーマーを別のホームリージョンに割り当てることができます。
別の例として、ビデオ会議会社で働いているとしましょう。各電話会議のメタデータは特定のリージョンに割り当てられます。発信者は、最も近いリージョンを利用してレイテンシーを最小限に抑えることができます。リージョンが停止した場合、グローバルテーブルを使用すると、システムは、データのレプリケートされたコピーが既に存在する別のリージョンに呼び出しの処理を移動できるため、すばやく回復できます。