We’re sorry we missed you at re:Invent, but we can still meet!

データベースのキャッシュ: Momento CacheはDynamoDBをキャッシュする最も簡単な方法です。

Momentoは、DynamoDBのための透過的なデータベース・キャッシュを提供します。DAXは開発者にとって不十分です。

Ellery Addington-White
著者

Share

私は、DynamoDB Accelerator(DAX)がDynamoDBをキャッシュする透過的な方法であり、必要最小限のコード変更でエンドポイントを変更するだけで、DynamoDBをより速く、より弾力的にしてくれると期待していました。残念ながら、これは現実ではありませんでした。ほとんどの開発者がそうであるように、私もキャッシュを追加するような実験を素早く(数分)、しかも値段なしで行えるようになりたいと思っています。

DynamoDBのテーブルを作るのには1分もかからないが、DAXクラスタを作るときには選択肢に圧倒されます。これらの選択肢には、インスタンスタイプ、レプリカ数、ゾーン、VPC(まだVPCに入っていない場合、スタック全体をリファクタリングしなければならない)などが含まれます。これらは、開発者としての私の速度と、より良いエンドユーザー・エクスペリエンスを提供するビジネスの邪魔をします。言うまでもないが、どれも透明性がありません。データベースのキャッシュはもっと簡単であるべきです。

モメントの登場です。

Gif of Momento entering a room.

Momento Cacheは、あなたのスタックに素早く簡単に統合できます。このように、わずか5行のコードでDynamoDBを高速化することができます。DAXの反省から、私は開発者がコード1行でコードベース全体のDynamoDBをキャッシュできるように、さらに高速化したいと考えました。ミドルウェアの力のおかげで、私はそれを実現することができた!

const db = DynamoDBDocumentClient.from(new DynamoDBClient({}));
db.middlewareStack.use(getCachingMiddleware());

DynamoDBの基本的なread-asideキャッシュを有効にしました(お遊びで、これを “MAX “と呼ぶことにします)。DynamoDBキャッシュの実装速度を最大化するには、”MAX “を追加し、JavaScript DynamoDBクライアントのインスタンス化方法を変更するだけです。これで完了です。

Momento Cacheを使えば、簡単に(しかも無料で!)データベースの最適化を試すことができます。今すぐお試しください!

では、どうすればうまくいったのか?

少し裏話をすると、これはAWSがV3 JavaScript SDKV2 Go SDKといったSDKに追加し始めた新しいミドルウェアスタックをいじくりまわした後に生まれました。しかし、V3 JS SDKでDAXがサポートされていないことにがっかりしました。この問題を解決するために私が行ったハッキングを紹介しましょう:

import {
CacheGet,

  LogFormat,

  LogLevel,

  SimpleCacheClient,

} from '@gomomento/sdk';

const CommandCacheAllowList = [

  'GetItemCommand'

];

const cacheName = 'default';

const authToken = process.env.MOMENTO_AUTH_TOKEN;

if (!authToken) {

  throw new Error('Missing required environment variable MOMENTO_AUTH_TOKEN');

}

const defaultTtl = 300;

const momento = new SimpleCacheClient(authToken, defaultTtl, {

  loggerOptions: {

    level: LogLevel.INFO,

    format: LogFormat.JSON,

  },

});

export const getCachingMiddleware = () => {

  return {

    applyToStack: stack => {

      stack.add(

        (next) => async args => {

          // Check if we should cache this command

          if (CommandCacheAllowList.includes(args.constructor.name)) {

            const itemCacheKey = getCacheKey(args);

            if (!args.input.ConsistentRead) {

              // Check and see if we already have item in cache

              const getResponse = await momento.get(cacheName, itemCacheKey);

              if (getResponse instanceof CacheGet.Hit) {

                // If item found in cache return result and skip DDB call

                return {

                  output: {

                    $metadata: {},

                    Item: JSON.parse(getResponse.valueString()),

                  },

                };

              }

            }

            // If we didn't get cache hit let normal call path go through and then try cache result for next time

            const result = await next(args);

            if (result.output.Item != undefined) {

              await momento.set(

                cacheName,

                itemCacheKey,

                JSON.stringify(result.output.Item)

              );

            }

            return result;

          } else {

            return await next(args);

          }

        },

        { tags: ['CACHE'] }

      );

    },

  };

}

function getCacheKey(args) {

  return args.input.TableName + JSON.stringify(args.input.Key);

}

また、Lambda関数を使用する場合、VPCにデプロイする必要性を減らしたり、アイドル状態でも料金を支払わなければならない専用のキャッシュノードをデプロイする必要性を減らしたりして、よりすっきりとしたアーキテクチャを実現できます。このアプローチは、他のAWSサービスへのAPI呼び出しにも拡張可能でしょう。もし “MAX “が便利だと感じたら、Discordで教えてほしい。

JS開発者の皆さん、AWS JavaScript SDKのv3を使用している場合でも、DynamoDBをキャッシュするための道筋を示すことで、新年が少しでも明るいものになれば幸いです。

試してみて、感想を私(@elleryaw)にツイートしてください!

Share