Amazon Web Services ブログ
Amazon DynamoDB グローバルテーブルを使用してマルチリージョンアーキテクチャを強化する方法
AWS のお客様は、自社のアプリケーションを複数の AWS リージョンに展開することで、世界中に広がっているユーザーがアプリケーションを利用できるようにしたいと近年ますます考えるようになってきています。世界中のユーザーは、アプリケーションに高速なパフォーマンスを期待しているのです。
この記事では、Amazon DynamoDB を使用して、複数の AWS リージョンにデプロイされたグローバルバックエンドのデータベースを強化する方法について説明します。ここでは DynamoDB グローバルテーブルを使用します。これは完全マネージド、マルチリージョンかつマルチマスターのデータベースを提供するもので、世界中のどこにいても低レイテンシーのデータアクセスをユーザーに提供できます。
マルチリージョンアーキテクチャを使用する理由
AWS の顧客は、通常、以下の 2 つの理由から、マルチリージョンアーキテクチャを希望します。
- 待ち時間を短縮し、アプリの操作性を向上させるため。
- 災害からの復旧を容易にするため。
1.低レイテンシーのアプリケーションでユーザーエクスペリエンスを向上させる
ネットワークのレイテンシーとネットワークのスループットは、ネットワークのパフォーマンスと品質を定義するために使用される重要な要素です。レイテンシーは、データパケットがエンティティ間を行き来するのにかかる時間であり、スループットは、特定の期間中にエンティティ間で送信されるデータ量のことです。ウェブアプリケーションのパフォーマンスと成功は、そのネットワークのパフォーマンスと品質に対するユーザーの認識に直接関係してきます。
世界中のコンテンツプロバイダは、Amazon CloudFront などのコンテンツ配信ネットワークを使用して、特にコンテンツが静的な場合 (画像、ビデオ、JavaScript ライブラリなど)、ユーザーにコンテンツをより迅速に提供します。静的コンテンツは、グローバルに分散したキャッシングサーバーのネットワークを使用すれば、ユーザーにとってローカルであるかのように扱われ、その静的コンテンツの配信の質が向上します。言い換えれば、バックエンドの起源がユーザーに近いほど、コンテンツのユーザーエクスペリエンスが向上する可能性が高くなります。
けれども、CloudFront が静的コンテンツの配信の問題を解決したとしても、バックエンドではまだいくつかの動的呼び出しが必要であったり、バックエンドサーバーが離れている可能性があったりして、リクエストにミリ秒の時間が余分にかかってきてしまいます。たとえば、ユーザーがヨーロッパにいるけれど、バックエンドが米国またはオーストラリアにある場合、それぞれ約 140 ミリ秒と 300 ミリ秒の追加の待ち時間がかかります。これらの遅延は、数多くの一般的なゲーム、e コマースプラットフォームやその他のインタラクティブアプリケーションにとって受け入れがたいものです。レイテンシーは顧客の行動に影響を及ぼします。レイテンシーが低くなると、ユーザーエンゲージメントが高まります。
テクノロジーが進歩し、拡張現実 (AR)、仮想現実 (VR)、複合現実 (MR) が出現したことに伴い、さらに没入感と現実感を必要となったため、開発者は厳しいレイテンシー要件を持つアプリケーションを開発する必要に迫られています。したがって、ローカルで利用できるアプリケーションとコンテンツを持つことはこれまで以上に重要になってきます。
2.災害からの復旧を容易にする
たとえば、アプリケーションがある AWS リージョンにデプロイされ、アプリケーションが複数のサービスで構成されているとします。アプリケーションにとってこれらのサービスのうちの 1 つが非常に重要で、そこに問題が発生している場合、トラフィックを健全なリージョンに移して顧客の不満を防ぐことを考えるかもしれません。失敗は時々起こり、失敗したときは、問題の影響を軽減することが重要です。マルチリージョンアーキテクチャを使用すると、災害復旧を容易に行えます。
マルチリージョン、アクティブ/アクティブアーキテクチャの構築
2 つの最も一般的に使用されるマルチリージョンアーキテクチャ構成は、アクティブ/パッシブおよびアクティブ/アクティブ構成です。アクティブ/パッシブアーキテクチャ構成は、通常、少なくとも 2 つのリージョンを含みます。ただし、すべてのリージョンが同時にトラフィックを処理するわけではないため、「アクティブ/パッシブ」と名付けられています。 構成に 2 つのリージョンが含まれている場合、一方のリージョンはアクティブにトラフィックを処理する一方、第 2 のリージョンはパッシブで、アクティブリージョンに問題が発生した場合にフェールオーバーをサポートする準備ができます。
アクティブ/アクティブ構成は、少なくとも 2 つのリージョンを含みます。一方のリージョンがアクティブにトラフィックを処理し、他方がパッシブであるアクティブ/パッシブ構成とは異なり、アクティブ/アクティブ構成では、すべてのリージョンが同じ種類のサービスをアクティブに実行し、トラフィックを同時に処理します。アクティブ/アクティブ構成の主な目的は、リージョン間のロードバランシングを達成することです。これには、サービストラフィックを最速のエクスペリエンスを提供するリージョンにルーティングする、レイテンシーベースのルーティングを使用することがよくあります。
マルチリージョン、アクティブ/アクティブアーキテクチャ構成を使用するには、次のいくつかの要件を満たす必要があります。
- サービスがステートレスであること。
- アクティブ/アクティブ構成内のどのリージョンからも、データを読み書きすることができること。
- リージョン間のデータのレプリケーションは、高速で信頼性の高いものであること。
最初の要件は非常に単純で、アプリケーションのローカル状態は維持されませんが、2 つ目と 3 つ目の要件は以前から困難なものでした。これは、データの変更を非同期的にレプリケートし、これらのリージョン間の競合を解決するためのコードを記述する必要があり、時間と労力を要する作業が必要となるためです。
DynamoDB グローバルテーブルなどの分散データストアの場合、非同期レプリケーションはプライマリノードとレプリカを切り離します。プライマリノードで実行された変更は数秒以内にレプリカにレプリケートされます。このタイプのレプリケーションは、結果整合性と呼ばれます。システムが結果整合性を達成すると、レプリカコンバージェンスが達成されたことになります。
レプリカコンバージェンスを達成するには、システムは分散データの複数のコピー間の違いを調整する必要があります。調整の最も一般的なアプローチは、「last writer wins」と呼ばれます。この競合解決メカニズムにより、すべてのレプリカが最新の更新に合意し、すべてが同じデータを持つ状態に収束します。
数年前、マルチリージョンアーキテクチャを導入する際は、リージョン間のセキュリティで保護された VPN 接続を設定して、データを非同期にレプリケートすることが標準的な方法でした。これらの接続の展開と管理は容易になりましたが、接続は引き続きインターネットを経由し、ルーティングとレイテンシーの突然の変更から影響を受けるため、常に良好なレプリケーションを維持することは困難です。
この問題を克服するため、AWS の副社長兼上級技術者である James Hamilton は、これから AWS では、世界中で冗長 100 ギガビットのイーサネット (GbE) リンクを搭載した高帯域幅のグローバルネットワークインフラストラクチャを提供することを発表しました。
結果として、AWS リージョンは現在、公衆インターネットと比較して低コストでより一貫したリージョン間ネットワークレイテンシーを提供する、プライベートなグローバルネットワークバックボーンに接続されています。 利点は明らかで、次のものがあります。
- レイテンシーの改善、パケットロスの低減、全体的な品質の向上。
- ネットワーク相互接続容量の競合が回避される。
- 優れた運用管理。
DynamoDB グローバルテーブルは、このグローバルネットワークバックボーンを使用して、グローバルに分散したユーザーのためにグローバルに分散したアプリケーションを構築できるようにします。グローバルテーブルを使用すると、リージョン間でデータをレプリケートして更新の競合を解消するという困難な作業がなくなり、アプリケーションのビジネスロジックに集中できるようになります。グローバルテーブルは、DynamoDB が単一ユニットとして扱う複数のレプリカテーブル (選択したリージョンごとに 1 つ) で構成されます。
titleグローバルテーブルは、DynamoDB が単一ユニットとして扱う複数のレプリカテーブルで構成されていますtitlealtグローバルテーブルは、DynamoDB が単一ユニットとして扱う複数のレプリカテーブルで構成されています
グローバルテーブルを作成する方法
DynamoDB テーブルを作成するときは、テーブル名のほか、そのテーブルのプライマリキーを指定する必要があります。プライマリキーはテーブルの各アイテムを一意に識別し、2 つのアイテムが同じキーを持てないようにします。グローバルテーブルでは、すべてのレプリカテーブルが同じテーブル名と同じプライマリキーを共有します。グローバルテーブルはマルチマスターデータベースであるため、アプリケーションはいずれかのレプリカテーブルにデータを書き込むことができます。DynamoDB は、これらの書き込みを、選択した AWS リージョン内の他のレプリカテーブルに自動的に伝播します。
グローバルテーブルを作成するには、DynamoDB コンソールを開き、プライマリキーでテーブルを作成します。プライマリキーはシンプル (パーティションキーのみ) またはコンポジット (パーティションキーとソートキーを組み合わせたもの) にすることができます。
コンソールでは、MyGlobalTable
という名前のテーブルを、item_id
をプライマリキーとして作成し、[作成] を選択します。このテーブルは、グローバルテーブルの最初のレプリカテーブルとして機能します。
コンソールで、item_id をプライマリキーとして MyGlobalTable というテーブルを作成し、次に [Create] を選択します
グローバルテーブルを作成するには、次のスクリーンショットに示すように、AWS マネジメントコンソールで次の操作を実行します。
- AWS マネジメントコンソールから [Global Tables] を選択します。
- [Enable streams] を選択します。
グローバルテーブルは DynamoDB Streams を使用してレプリカ間の変更を伝播します。DynamoDB ストリームは、DynamoDB テーブル内のアイテムの変更に関する情報の順序付けられたフローです。アプリケーションがテーブル内のアイテムを作成、更新、または削除するたびに、ストリームは変更されたアイテムのプライマリキー属性を持つストリームレコードを書き込みます。
AWS マネジメントコンソールから [Global Tables] タブを選択し、次に [Enable streams] を選択します。AWS マネジメントコンソールから [Global Tables] タブを選択し、次に [Enable streams] を選択します。
注: 次のスクリーンショットに示すように、使用中のストリームのビュータイプ (新しい画像と古い画像) を示すポップアップが表示されることがあります。これは、テーブル内のデータが変更されるたびに、テーブル内のアイテムの新しい画像と古い画像の両方がストリームに書き込まれることを意味します。このストリームは、リージョン間でデータをレプリケートするために使用されます。
ストリームを有効にしたら、[Add region] を選択して、グローバルテーブルに新しいリージョンを追加します (次のスクリーンショットを参照)。レプリカテーブルをデプロイする AWS リージョンを選択し、[Continue] を選択します。
この例では、私はヨーロッパにいるので、欧州内でのみデータをレプリケートしたいので、グローバルテーブルを形成するリージョンとして欧州 (フランクフルト) と欧州 (アイルランド) を選択します。
注: リージョン間でデータをレプリケートするときは、常に法律に従って行います。具体的なコンプライアンス要件には、大陸 (ヨーロッパ、北米など) やリージョン間でデータをレプリケートできないことがあるかもしれません。
リージョンを追加すると、選択したリージョンでテーブルを作成するプロセスが開始されます。数秒後に、新しく作成されたグローバルテーブルを形成する異なるリージョンを見ることができるはずです。グローバルテーブルは、DynamoDB が単一のユニットとして扱う複数のレプリカテーブル (任意のリージョンごとに 1 つ) で構成されていることを忘れないでください。したがって、すべてのレプリカには同じテーブル名と同じプライマリキースキーマがあります。
数秒後に、新しく作成されたグローバルテーブルを形成する異なるリージョンを見ることができるはずです。数秒後に、新しく作成されたグローバルテーブルを形成する異なるリージョンを見ることができるはずです
以前は、グローバルテーブルを 2 つのリージョン (欧州 (フランクフルト)、欧州 (アイルランド)) に作成していました。AWS マネジメントコンソールを使用してグローバルテーブルを作成しましたが、AWS Command Line Interface (CLI) を用いて同じことができます。AWS CLI は、常に良いものとされる自動化と再現性を可能にします。
AWS CLI を使用して 2 つのリージョンにグローバルテーブルを作成するには、次の手順を実行します。
- 端末で AWS CLI を使用して、ストリームを有効にした初期テーブルを作成します。グローバルテーブルはストリームを使用してレプリカ間の変更を伝播することを忘れないでください (この例では、欧州 (アイルランド) リージョンにテーブルを作成しています)。
上記のコマンドの出力は、次のようになります (xxxxxxxxxxxx をご自身の AWS アカウント番号に置き換えてください)。
- ストリームが有効になっている別のリージョンに同一のテーブルを作成します (ここでは 欧州 (フランクフルト) リージョンに同じテーブルを作成しています)。
上記のコマンドにより、以下が返されます。
- 先に作成したレプリカテーブルで構成されるグローバルテーブルを作成します。端末で次のコマンドを実行します。
上記のコマンドから、次のようなものを出力するはずです (xxxxxxxxxxxxをご自身の AWS アカウント番号に置き換えてください)。
AWS マネジメントコンソールを使用して、グローバルテーブルが正常に作成されたことを確認できます。
容量について考えてみましょう
この記事ではグローバルテーブルの作成について触れてきましたが、アプリケーションを拡張する上で重要なのはデータベースレベルでの容量管理です。多くのアプリケーションワークロードは予測不可能 (例えば、flash salesのような短期間で多くの売上を見込むセールスイベントや、ウイルスコンテンツを含むソーシャルネットワーキングなど) か、周期的です。
カスタマーエクスペリエンスを高いレベルで維持するためには、データベースはトラフィックパターンに関係なく拡張可能でなければならず、手動の作業を要してはなりません。DynamoDB の Auto Scaling は、実際のトラフィックパターンに応じて、AWS Application Auto Scaling を使用してプロビジョニングされたスループットの容量を動的に調整します。Auto Scaling では、テーブルまたはグローバルセカンダリインデックスは、トラフィックの突然の増加に対処するためにプロビジョニングされた読み書きの容量を増やすことができます。トラフィックが減少すると、Auto Scaling によってスループットが低下するので、未使用のプロビジョニングされた容量への支払いは発生しません。
Auto Scaling を使用して、グローバルテーブルのスループット容量の設定を管理することをお勧めします。グローバルテーブルのスループット容量を手動で管理する場合は、DynamoDB のベストプラクティスに従ってデータのレプリケーション問題を回避してください。
グローバルテーブルで Auto Scaling を有効にするには、DynamoDB コンソールに移動します。グローバルテーブルページで、
- 次のスクリーンショットに示すように [Capacity] タブを選択します。
- Auto Scaling セクションの [Consistent settings across all regions] を選択し、変更を適用するには [Save] を選択します。title[Capacity] タブを選択しますtitle[Capacity] タブを選択します
(たった今行ったように) グローバルテーブルを変更する場合は、DynamoDB コンソールまたは UpdateGlobalTableSettings
コールを使用して、グローバルテーブル内のすべてのレプリカテーブルと、一致するセカンダリインデックスに自動的に変更を適用します。これにより、プロビジョニングされた書き込み容量の設定が、グローバルテーブル内のレプリカテーブルとセカンダリインデックス間で一貫していることが保証されます。
UpdateTable
、RegisterScalableTarget
、または PutScalingPolicy
コールの使用はお勧めしません。特定のレプリカテーブルのみを対象としており、変更が他のレプリカテーブルに自動的に適用されないためです。手動ですべてのレプリカテーブルに同じ変更を加える必要があります。レプリカテーブル全体で書き込み容量が一貫していないと、データのレプリケーション問題が発生する可能性があります。
詳細については、「Managing Throughput Capacity Automatically with DynamoDB Auto Scaling」をご覧ください。
DynamoDB グローバルテーブルへのアクセス
DynamoDB グローバルテーブルにアクセスして使用するには、AWS マネジメントコンソールと AWS CLI を使用することができます。ただし、AWS マネジメントコンソールと AWS CLI をテスト用または小さなスクリプト用のみに使用することをお勧めします。
大規模なプロジェクトの場合や、DynamoDB を最大限に活用するには、DynamoDB SDK を使用してアプリケーションコードを記述する必要があります。SDK は、Java、ブラウザの JavaScript、.NET、Node.js、PHP、Python、Ruby、C ++、Go、Android、および iOS をサポートしています。
AWS マネジメントコンソールを使用した簡単な例と、AWS CLI を使用した別の例を見てみましょう。
AWS マネジメントコンソールを使用してグローバルテーブルを更新する
AWS マネジメントコンソールを使用してアイテムをグローバルテーブルに追加するには、以下の手順を実行します。
- DynamoDB グローバルテーブルがレプリケートされるリージョンを選択します (この例では、欧州 (フランクフルト) リージョンのテーブルを選択します)。
- MyGlobalTable の [Items] を選択します。
- [Create Item] を選択します。
MyGlobalTable ページで [Items] タブを選択し、[Create Item] を選択しますtitleMyGlobalTable ページで [Items] タブを選択し、[Create Item] を選択しますこれで、グローバルテーブルにアイテムを追加することができます。私はitem_id: (String) foobar
を追加することを選択しました。これは、単にfoobar
のストリングを item_id の値として追加することを意味します。私は item_id: (String) foobar を追加することを選択しました。これは、単に foobar のストリングを item_id の値として追加することを意味します
私は item_id: (String) foobar を追加することを選択しました。これは、単に foobar のストリングを item_id の値として追加することを意味します - アイテムをテーブルに保存するには、[保存] を選択します。
- [Items] タブを選択して、アイテムがテーブルに保存されていることを確認できます。
title[Item] タブを選択して、テーブルにアイテムが保存されていることを確認しますtitlealt[Item] タブを選択して、テーブルにアイテムが保存されていることを確認しますalt - また、商品が欧州西部 (アイルランド) リージョンでレプリケートされていることを確認したいと思います。[Global Tables] タブを選択し、2 番目のリージョンである欧州西部 (アイルランド) を選択します。
- 欧州西部 (アイルランド) コンソールのグローバルテーブルが開きます。次に、[Items] タブを選択して、
item_id
:foobar
が正常にレプリケートされていることを確認します。
ご覧のとおり、item_id
: foobar
が正常にレプリケートされ、アイテムの起源は欧州 (フランクフルト) リージョンのコードである eu-central-1
になっています。
DynamoDB グローバルテーブルによって作成された新しいフィールドに気付きましたか? クロスリージョンレプリケーションプロセスでは、aws:rep:delete
、aws:rep:updateregion
、および aws:rep:updatetime
属性が追加されるため、作成されたアイテムの起源をテーブルで追跡することができます。アプリケーションではこれらの属性を使用しますが、グローバルテーブルではこれらの属性を用いてテーブルのデータをリージョン間で同期させているため、変更しないでください。
AWS CLI を使用してグローバルテーブルを更新する
AWS CLI を使用して DynamoDB グローバルテーブルにアイテムを追加するには、端末で次のコマンドを実行します。欧州西部 (アイルランド) リージョンのアイテムを保管することにします。
次に、欧州 (フランクフルト) リージョンで作成されたアイテムを取得することによって、アイテムが前述のコマンドでテーブル内に作成されたことを確認するためのテストを行います。
前述のコマンドの出力は、次のようになるはずです。
表示されているように、item
: foobarcli
がグローバルテーブルに正常にレプリケートされました。
Python SDK を使用してグローバルテーブルを更新する
AWS Python SDK を使用して DynamoDB グローバルテーブルにアイテムを追加するには、次の汎用 Python コードを Lambda アプリケーションの開始点として使用できます。
ハンドラー lambda_function.put_to_dynamo
を使用してこの Lambda 関数を呼び出して、次のテストイベントでテストできます。
同様に、AWS Python SDK を使用して DynamoDB グローバルテーブルからアイテムを読み取るには、次の汎用 Python コードを Lambda アプリケーションの開始点として使用できます。
ハンドラー lambda_function.get_from_dynamo
を使用してこの Lambda 関数を呼び出して、次のテストイベントでテストできます。
注: Lambda 関数の Python AWS SDK を使用した前述の例では、どちらも環境変数として DynamoDB テーブルと AWS Region の名前を設定することを想定しています。
まとめ
このブログ記事を読んで、マルチリージョンアーキテクチャの中心にある DynamoDB グローバルテーブルを使用してみようと思われたら幸いです。グローバルテーブルは、完全マネージド、マルチリージョンかつマルチマスターのデータベースを提供します。万一、リージョン全体の分離や劣化が発生した場合でも、アプリケーションは高いパフォーマンスを発揮し、利用し続けることができます。また、リージョン間でデータベースをレプリケートし、更新の競合を解決するためにコードを記述し、維持することを心配する必要はありません。
著者について
Adrian Hornsby は、AWS の技術伝道者です。お客様が AWS のサービスを理解するサポートをしていないときは、ロッククライミングをし、フリスビーを投げ、ムエタイを練習しています。