こんにちは、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 で作成します。
lib/cdk-sample-stack.ts
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
メソッドを使用することによりパラメーターを取得します。
lib/cdk-sample-stack.myFunction.ts
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
を指定することによりキャッシュ期間を設定します。
lib/cdk-sample-stack.myFunction.ts
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
メソッドを使用することにより複数のパラメーターをクエリにより取得します。
lib/cdk-sample-stack.myFunction.ts
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、値の属性名をカスタマイズすることができます。
lib/cdk-sample-stack.myFunction.ts
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 テーブルを単一のキー/バリューのみのデータ格納領域として使用するのであれば、選択肢としてありではないでしょうか。
以上