ASP.NET Core アプリケーションからAmazon DynamoDB Accelerator(DAX)を利用する

はじめに

こんにちは、エンジニアの川上と申します。

ASP.NET Core でDAXを利用しようとしたところ、インターネット上に記事が少なくて苦戦したため、自らが記事を書くことにしました。

なぜDAXを使おうと考えたか

DAXはDynamoDBからのReadを高速化するための、インメモリキャッシュです。
DAXクラスタに対して更新リクエストを発行すると、ライトスルー方式で更新内容をクラスタ内のノードとDynamoDBのテーブルに反映してくれるという特徴があります。
通常、データベースのキャッシュを考えると、更新結果を反映させるためにキャッシュのTTLに気を使う必要がありますが、上記により更新結果の即時反映がしやすくなっています。
更新頻度が少なく、read heavyなワークロードであるが、更新があった場合は即時反映したいデータを扱うケースがあったため、上記特性がよいと考えました。

※DAXはGetとQueryでキャッシュの扱いが異なりますので、注意が必要です。利用する場合は公式のドキュメントを参照して動作について理解することをお勧めします。

どうやって利用するか

本利用例はDAXをDynamoDBにアクセスする際に必ず利用するようにする実装例となります。
ケースによってDAXを利用するしないを分けたい場合は、それに沿った修正が必要です。

以下のパッケージをnugetで取得します。

  • AWSSDK.DAX.Client
  • AWSSDK.DynamoDBv2
  • AWSSDK.Extensions.NETCore.Setup

Startup.cs でDynamoDBクライアントをサービスコンテナに追加します。
DAXクラスタへはDAXクラスタが稼働するVPC内からしかリクエストが届かないため、ローカルデバック時にはDAXを利用しないよう設定可能にしています。
DAXのクライアントクラスとDynamoDBのクライアントクラスは同じIAmazonDynamoDBインターフェースを実装しているため、切り替えが可能です。
DAXのクライアント(ClusterDaxClient)を利用する場合は、コンフィグとしてDAXクラスタのエンドポイントとポートを追加で設定する必要があるため、AddAWSServiceを使った登録は利用しません。

if (Configuration.GetValue<bool>("DAX:UseDax"))
{
    services.AddSingleton<IAmazonDynamoDB, ClusterDaxClient>(provider =>
    {
        var clientConfig = new DaxClientConfig(Configuration.GetValue<string>("DAX:Host"), Configuration.GetValue<int>("DAX:Port"))
        {
            RegionEndpoint = RegionEndpoint.GetBySystemName(Configuration.GetValue<string>("AWS:Region")),
            AwsCredentials = FallbackCredentialsFactory.GetCredentials(),
        };

        return new ClusterDaxClient(clientConfig);
    });
}
else
{
    services.AddAWSService<IAmazonDynamoDB>();
}

appsettings.jsonに設定を追加します。
ローカルデバック時にはDAXを利用しないようにするため、appsettings.Development.jsonにはDAX:UseDaxの値はfalseにします。

{
  "AWS": {
    "Region": "ap-northeast-1"
  },
  "DAX": {
    "UseDax": true,
    "Host": "[dax clusterのエンドポイント]",
    "Port": 8111
  }
}

利用サンプルです。
DIを利用しているため、利用側はDAX / DynamoDBを意識せずに利用できます。
※DAXとDynamoDBではキャッシュ層の有無による動作差異がありますので、その辺は注意が必要です。

namespace XXXXXX
{
    public class Xxxxxxx : IXxxxxxx
    {
        private readonly IAmazonDynamoDB _dynamoDbClient;

        public Xxxxxxx(
            IAmazonDynamoDB dynamoDbClient,
        {
            _dynamoDbClient = dynamoDbClient;
        }

        public async Task<Dictionary<string, AttributeValue>> ReadData(string key)
        {
            var response = await _dynamoDbClient.GetItemAsync(new GetItemRequest
            {
                TableName = "testtable",
                Key = new Dictionary<string, AttributeValue>
                {
                    {"key", new AttributeValue {S = key}},
                },
            });

            return response.Item;
        }
    }
}

感想

ASP.NET CoreでAWSのサービスを利用する場合、AddAWSServiceを利用して登録する実装が通常かと思いますが、DAXを利用する場合は素直に利用できずに苦労しました。
おかげでAddAWSServiceが何をしているのか中を読む必要が発生し、理解を深められたことが結果的によかったかもしれません。
しかし、そもそも公式のライブラリで利用しやすくしてくれると嬉しいので、今後のアップデートに期待します。