Powertools for AWS Lambda (TypeScript) を使って DynamoDB テーブルからのデータ取得をキャッシュしてみた

Powertools for AWS Lambda (TypeScript) を使って DynamoDB テーブルからのデータ取得をキャッシュしてみた

Clock Icon2023.07.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 Delivery部の若槻です。

以前に Powertools for AWS Lambda (TypeScript) を使って AWS Systems Manager Parameter Store からのデータ取得のキャッシュを試してみました。

この Powertools ですが、DynamoDB にも対応しており、パラメーター保管領域として使用しているテーブルからのデータ取得のキャッシュを容易に実装することもできます。

試してみた

Powertools for AWS Lambda (TypeScript) を使って DynamoDB からのデータ取得のキャッシュを試してみます。

インストール

必要なモジュールをインストールします。

npm install @aws-lambda-powertools/parameters @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb

検証環境の作成

検証環境として、DynamoDB テーブル 3 つおよび Lambda 関数および AWS CDK で作成します。

import {
  aws_dynamodb,
  aws_lambda_nodejs,
  aws_lambda,
  RemovalPolicy,
  Stack,
  StackProps,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  public readonly myFileObjectKey: string;

  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    // my-table:PK=id
    const myTable = new aws_dynamodb.Table(this, 'myTable', {
      tableName: 'my-table',
      partitionKey: { name: 'id', type: aws_dynamodb.AttributeType.STRING },
      billingMode: aws_dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: RemovalPolicy.DESTROY,
    });
    // my-table2:PK=id, SK=sk
    const myTable2 = new aws_dynamodb.Table(this, 'myTable2', {
      tableName: 'my-table2',
      partitionKey: { name: 'id', type: aws_dynamodb.AttributeType.STRING },
      sortKey: { name: 'sk', type: aws_dynamodb.AttributeType.STRING },
      billingMode: aws_dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: RemovalPolicy.DESTROY,
    });
    // my-table3:PK=customId, SK=customSk
    const myTable3 = new aws_dynamodb.Table(this, 'my-table3', {
      tableName: 'my-table3',
      partitionKey: {
        name: 'customId',
        type: aws_dynamodb.AttributeType.STRING,
      },
      sortKey: { name: 'customSk', type: aws_dynamodb.AttributeType.STRING },
      billingMode: aws_dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: RemovalPolicy.DESTROY,
    });

    // Lambda 関数
    const myFunction = new aws_lambda_nodejs.NodejsFunction(
      this,
      'myFunction',
      {
        functionName: 'myFunction',
        architecture: aws_lambda.Architecture.ARM_64,
        runtime: aws_lambda.Runtime.NODEJS_18_X,
      }
    );

    // 読み取り権限付与
    myTable.grantReadData(myFunction);
    myTable2.grantReadData(myFunction);
    myTable3.grantReadData(myFunction);
  }
}

パラメーター取得(キャッシュなし)

my-table:PK=id からのパラメーター取得です。既定では PK は id というキー名である必要があります。dynamoDBProvider を構成し、get メソッドを使用することによりパラメーターを取得します。

import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb';

const dynamoDBProvider = new DynamoDBProvider({ tableName: 'my-table' });

export const handler = async (): Promise<any> => {
  const value = await dynamoDBProvider.get('my-parameter');
  return value;
};

my-table に id: my-parameter のアイテムを作成します。ここでパラメーターの値としたい属性名を value とする必要があります。

aws dynamodb put-item \
  --table-name my-table \
  --item '{"id": {"S": "my-parameter"}, "value": {"S": "my-value"}}'

Lambda 関数を実行すると値が取得されました。

$ aws lambda invoke --function-name myFunction response.json
$ cat response.json
"my-value"

ここで、get は既定ではキャッシュ期間は 0 なので、変更後の値はすぐに取得されます。

id: my-parameter のアイテムの value 属性の値を更新します。

$ aws dynamodb put-item \
  --table-name my-table \
  --item '{"id": {"S": "my-parameter"}, "value": {"S": "new-my-value"}}'

Lambda 関数を実行すると更新後の値が取得されました。

$ aws lambda invoke --function-name myFunction response.json
$ cat response.json
"new-my-value"

パラメーター取得(キャッシュあり)

続いて先程と同じテーブルでキャッシュを有効にしてパラメーター取得を行います。get メソッドで maxAge を指定することによりキャッシュ期間を設定します。

import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb';

const dynamoDBProvider = new DynamoDBProvider({ tableName: 'my-table' });

export const handler = async (): Promise<any> => {
  const value = await dynamoDBProvider.get('my-parameter', { maxAge: 60 });
  return value;
};

my-table に id: my-parameter のアイテムを作成します。

aws dynamodb put-item \
  --table-name my-table \
  --item '{"id": {"S": "my-parameter"}, "value": {"S": "my-value"}}'

Lambda 関数を実行すると値が取得されました。

$ aws lambda invoke --function-name myFunction response.json;cat response.json
"my-value"

ここで値を更新します。

id: my-parameter のアイテムの value 属性の値を更新します。

$ aws dynamodb put-item \
  --table-name my-table \
  --item '{"id": {"S": "my-parameter"}, "value": {"S": "new-my-value"}}'

前回 Lambda 関数実行から 60秒(キャッシュ期間)以内に再度実行すると、更新前の値が取得されました。キャッシュが働いていますね。

$ aws lambda invoke --function-name myFunction response.json;cat response.json
"my-value"

60秒(キャッシュ期間)経過後に再度実行すると、更新後の値が取得されました。キャッシュがクリアされています。

$ aws lambda invoke --function-name myFunction response.json;cat response.json
"new-my-value"

複数のパラメーター取得

my-table2:PK=id, SK=sk からのパラメーター取得です。既定では PK は id 、SK は sk というキー名である必要があります。dynamoDBProvider を構成し、getMultiple メソッドを使用することにより複数のパラメーターをクエリにより取得します。

import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb';

const dynamoDBProvider = new DynamoDBProvider({ tableName: 'my-table2' });

export const handler = async (): Promise<any> => {
  const values = await dynamoDBProvider.getMultiple('my-hash-key');
  return values;
};

ハッシュキー id: my-hash-key に対して複数のアイテムを作成します。get と同様にパラメーターの値としたい属性名を value とする必要があります。

aws dynamodb put-item \
  --table-name my-table2 \
  --item '{"id": {"S": "my-hash-key"}, "sk": {"S": "param-a"}, "value": {"S": "my-value-a"}}'
aws dynamodb put-item \
  --table-name my-table2 \
  --item '{"id": {"S": "my-hash-key"}, "sk": {"S": "param-b"}, "value": {"S": "my-value-b"}}'
aws dynamodb put-item \
  --table-name my-table2 \
  --item '{"id": {"S": "my-hash-key"}, "sk": {"S": "param-c"}, "value": {"S": "my-value-c"}}'

Lambda 関数を実行すると、指定したハッシュキーに対応する複数の値が取得されました。

$ aws lambda invoke --function-name myFunction response.json;cat response.json
{"param-a":"my-value-a","param-b":"my-value-b","param-c":"my-value-c"}

カスタマイズしたパラメーターの取得

続いて、my-table3:PK=customId, SK=customSk からのパラメーター取得です。DynamoDBProvider でオプションを指定することにより、PK、SK、値の属性名をカスタマイズすることができます。

import { DynamoDBProvider } from '@aws-lambda-powertools/parameters/dynamodb';

const dynamoDBProvider = new DynamoDBProvider({
  tableName: 'my-table3',
  keyAttr: 'customId',
  sortAttr: 'customSk',
  valueAttr: 'count',
});

export const handler = async (): Promise<any> => {
  const values = await dynamoDBProvider.getMultiple('my-hash-key');
  return values;
};

ハッシュキー customId: my-hash-key に対して、DynamoDBProvider で指定した属性名でアイテムを作成します。

aws dynamodb put-item \
  --table-name my-table3 \
  --item '{"customId": {"S": "my-hash-key"}, "customSk": {"S": "param-a"}, "count": {"N": "1"}}'
aws dynamodb put-item \
  --table-name my-table3 \
  --item '{"customId": {"S": "my-hash-key"}, "customSk": {"S": "param-b"}, "count": {"N": "2"}}'
aws dynamodb put-item \
  --table-name my-table3 \
  --item '{"customId": {"S": "my-hash-key"}, "customSk": {"S": "param-c"}, "count": {"N": "3"}}'

Lambda 関数を実行すると、指定したソートキーの値をキー、属性名を値として結果が取得されました。

$ aws lambda invoke --function-name myFunction response.json;cat response.json
{"param-a":1,"param-b":2,"param-c":3}

おわりに

Powertools for AWS Lambda (TypeScript) を使って DynamoDB テーブルからのデータ取得をキャッシュしてみました。

ユースケースは限られそうですが、DynamoDB テーブルを単一のキー/バリューのみのデータ格納領域として使用するのであれば、選択肢としてありではないでしょうか。

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.