📝

Amazon DynamoDB Accelerator とは

に公開

DynamoDB Accelerator (DAX) とインメモリアクセラレーション - Amazon DynamoDB

Amazon DynamoDB はスケールとパフォーマンスのために設計されています。ほとんどの場合、DynamoDB の応答時間は 1 桁台のミリ秒単位で測定できます。ただし、マイクロ秒の応答時間を必要とする一部のユースケースがあります。これらのユースケースでは DynamoDB Accelerator (DAX) が整合性データへのアクセス時に素早い対応を実現します。

DynamoDB のキャッシュ機能です。

機能概要

  • DynamoDB と互換性のあるキャッシュサービス
  • マイクロ秒単位での応答が可能
  • サーバー側の暗号化をサポート
  • VPC 環境で動作する
  • クラスターは EC2 インスタンスとして VPC 内に起動される
  • アプリケーションはクラスターのエンドポイントに接続する
  • クロスアカウントアクセスが可能

ユースケース

DynamoDB Accelerator (DAX) とインメモリアクセラレーション - Amazon DynamoDB

  • 迅速な読み込み応答時間を必要とするアプリケーション
    • リアルタイム入札、ソーシャルゲーム、トレーディングアプリケーションなど
  • 少数の項目を他のものよりも頻繁に読み込むアプリケーション
    • 人気商品の 1 日限りのセールを行う e コマースシステム
  • 読み込み負荷が高いがコストも重要なアプリケーション
  • 大規模データセットに対して繰り返し読み込みが必要なアプリケーション

DAX が最適ではないケース

DynamoDB Accelerator (DAX) とインメモリアクセラレーション - Amazon DynamoDB

  • 強整合性のある読み込みを必要とするアプリケーション
  • 読み込みでマイクロ秒の応答時間を要求しないアプリケーション
  • 基礎となるテーブルから繰り返される読み込みアクティビティをオフロードする必要がないアプリケーション
  • 書き込み負荷の高いアプリケーション
  • 読み込みの繰り返しが少ないアプリケーション

読み込み動作

DAX: 仕組み - Amazon DynamoDB

  • 読み込みは GetItem, BatchGetItem, Query, Scan API に対応
  • 結果整合性読み込みでは DAX でキャッシュヒットした場合は DAX から応答
  • 結果整合性読み込みでは DAX でキャッシュミスした場合は DynamoDB にアクセス
  • 強力な整合性のある読み込みでは DAX にキャッシュされない

書き込み動作

DAX: 仕組み - Amazon DynamoDB

  • 書き込みは BatchWriteItem, UpdateItem, DeleteItem, PutItem に対応
  • 書き込み API の動作は DynamoDB への書き込み後に DAX に書き込まれる書き込みスルー

DAX のコンポーネント

DAX クラスターコンポーネント - Amazon DynamoDB

  • ノード: DAX ソフトウェアを実行する 1 インスタンス
  • クラスター: ノードの集合
    • 1 つはプライマリノード、その他はリードレプリカ
  • クラスターエンドポイント: クラスター単位のエンドポイント
  • ノードエンドポイント: ノード単位のエンドポイント
    • クラスターエンドポイントの利用が推奨されている

試してみた

DAX クラスターを作成して性能を確認してみました。

01. DynamoDB テーブルの作成

以下の設定で作成しました。

  • テーブル名: DaxTestTable
  • パーティションキー: id (文字列)

上記以外はデフォルト設定です。

02. DAX クラスターの作成

以下の設定で作成しました。

  • クラスター名: dax-test-cluster
  • ノードファミリー: T 型ファミリー
  • ノードタイプ: dax.t2.small
  • ノード数: 3
  • ネットワークタイプ: IPv4
  • サブネットグループ: 新規作成
  • サブネットグループ名: dax-test-group
  • VPC ID: デフォルト VPC
  • サブネット: デフォルトサブネット 3 つ
  • セキュリティグループ: デフォルトセキュリティグループ
  • AZ の割り当て: 自動
  • DynamoDB アクセスのための IAM サービスロール: 新規作成
  • IAM ロール名: DAXServiceRole

上記以外はデフォルト設定です。






クラスター作成後にクラスターが利用可能になったことを確認します。

なお、ノードのインスタンスは EC2 コンソールには表示されないインスタンスでした。

03. EC2 インスタンスの作成

以下の設定で DAX にアクセスする EC2 インスタンスを作成しました。

  • AMI: Amazon Linux 2023
  • キーペア: 不要
    • インスタンスコネクトで接続します。
  • VPC: デフォルト
  • サブネット: デフォルト
  • セキュリティグループ: インバウンド、アウトバウンド全開放
  • インスタンスプロフィル: AdministratorAccess を付与したプロファイル

EC2 インスタンスの起動後、インスタンスコネクトで接続してアプリケーションを作成します。
endpoint の値は手順 02 で作成したクラスターのエンドポイントに置換してください。

$ sudo dnf update -y
$ sudo dnf install -y nodejs

$ mkdir dax-test
$ cd dax-test
$ npm init -y
$ npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb amazon-dax-client

$ cat <<'EOF' > dax-v3.js
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const {
  DynamoDBDocumentClient,
  PutCommand,
  GetCommand
} = require("@aws-sdk/lib-dynamodb");
const AmazonDaxClient = require("amazon-dax-client");

const dax = new AmazonDaxClient({
  endpoints: [
    "your-cluster-endopoint:8111"
  ]
});

const ddbClient = new DynamoDBClient({
  region: "ap-northeast-1",
  requestHandler: dax
});

const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);

async function run() {
  const tableName = "DaxTestTable";

  await ddbDocClient.send(
    new PutCommand({
      TableName: tableName,
      Item: {
        id: "1",
        message: "Hello from DAX (v3 CommonJS)"
      }
    })
  );

  const start = Date.now();

  const result = await ddbDocClient.send(
    new GetCommand({
      TableName: tableName,
      Key: { id: "1" }
    })
  );

  const end = Date.now();

  console.log("GetItem via DAX:", result.Item);
  console.log("Latency via DAX (ms):", end - start);
}

run().catch(console.error);
EOF

04. 動作確認

EC2 インスタンス内でアプリケーションを実行して以下のメッセージ表示されることを確認します。

$ node dax-v3.js
PutItem via DAX (v3 CommonJS) succeeded
GetItem via DAX (v3 CommonJS): { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency via DAX (ms): 21

05. DAX の有無での性能比較

DAX の有無でのレイテンシーを比較するため、DAX を使用しないアプリケーションも作成します。

$ cat <<'EOF' > dynamodb-direct.js
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const {
  DynamoDBDocumentClient,
  GetCommand
} = require("@aws-sdk/lib-dynamodb");

const ddbClient = new DynamoDBClient({
  region: "ap-northeast-1"
});

const ddbDocClient = DynamoDBDocumentClient.from(ddbClient);

async function run() {
  const tableName = "DaxTestTable";

  const start = Date.now();

  const result = await ddbDocClient.send(
    new GetCommand({
      TableName: tableName,
      Key: { id: "1" }
    })
  );

  const end = Date.now();

  console.log("DynamoDB Direct GetItem:", result.Item);
  console.log("Latency (ms):", end - start);
}

run().catch(console.error);
EOF

アプリケーション作成後、両方のアプリケーションを何度か実行します。

$ node dax-v3.js
GetItem via DAX: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency via DAX (ms): 22

# node dax-v3.js を複数回実行
GetItem via DAX: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency via DAX (ms): 27

GetItem via DAX: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency via DAX (ms): 30

GetItem via DAX: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency via DAX (ms): 21

GetItem via DAX: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency via DAX (ms): 24

$ node dynamodb-direct.js
DynamoDB Direct GetItem: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency (ms): 107

# node dynamodb-direct.js を複数回実行
DynamoDB Direct GetItem: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency (ms): 110

DynamoDB Direct GetItem: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency (ms): 102

DynamoDB Direct GetItem: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency (ms): 106

DynamoDB Direct GetItem: { id: '1', message: 'Hello from DAX (v3 CommonJS)' }
Latency (ms): 106

今回の場合、以下の結果を観測できました。

  • DAX 使用時: 2 桁ミリ秒での応答
  • DAX 不使用時: 3 桁ミリ秒での応答

以上より、DAX を使用した方がレイテンシーが小さいことを確認できました。

まとめ

今回は Amazon DynamoDB Accelerator について紹介しました。
どなたかの参考になれば幸いです。

参考資料

Discussion