はじめに
最近インメモリキャッシュサービスを格安で利用することができないかと色々調べていました。
(Elasticacheなどのサービスは高いのでなるべく無料のものを利用したい。)
その結果、Momentoというサービスを発見しましたので、今回はそれについて触ってみてLambdaへの実装までを実施しました。
Momentoとは ?
インメモリキャッシュのSaaSサービスです。正確にはMomento Cacheにてインメモリキャッシュを行うことができます。
AWS上でキャッシュを利用するとなると、ElastiCacheやAppSync(正確にはElasticache)などを利用す
毎月5GBまでのデータの登録は無料で利用することができるため、。
その後は1GBあたり0.50ドル課金されます。
スタンダードプラン以降はCloudWatch メトリクスへエクスポートすることも可能になります。
Momento設定内容
今回はMomento cache を作成して
キャッシュを作成するにはMomento Cache画面にて「キャッシュを作成」をクリックします。
以下のようにキャッシュ名とクラウドプロバイダー、リージョンを選択すればこれで完了です。
かなり簡単に作成することができました。
あとは、キャッシュを利用するための APIキーの発行です。API コンソールを作成して
からプロバイダーと権限を作成します。
以上で、momentoでの設定は完了になります。
超シンプルにキャッシュを作成することができました。
AWS Lambda + Momento でサーバレスキャッシングやってみた
次にAWS Lambda から Momento Cacheへ接続してみたいと思います。
複数の関数でmomentoパッケージを利用したいので今回はmomentoパッケージをLayer化して、
Lambda関数で利用したいと思います。
今回使用するLambdaランタイム環境はPython3.10とします。
- AWS CDK
1. Lambda Layer Package
PypiからMomento Python Client Libraryをインストールします。
以前投稿したように「invalid ELF header」によるELF headerの不一致によるエラーが発生するので、Lambdaの公式ランタイムのイメージ上でmomentoをインストールするようにします。
具体的な手順はこちらを参考にお願いします。
2. Lambda デプロイ
今回はCDKを使用してLambdaとLambdaLayerを作成してデプロイしようと思います。使用言語はTypeScriptで記述していこうと思います。
CDKの使い方についてはこちらを参考に。
CDKアプリケーションのエントリポイントは以下の通りです。./lib下のCDKアプリケーションのメインスタックを呼び出します。今回はLambdaとLambdaLayerのスタックを作成します。
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { LambdaFuncStack } from '../lib/lambda-func.ts';
import { LambdaLayerStack } from '../lib/lambda-layer.ts';
const app = new cdk.App();
new LambdaLayerStack(app, 'LambdaLayerStack', {});
new LambdaFuncStack(app, 'LambdaFuncStack', {});
Lambda Layerを作成するCDKアプリケーションを作成します。
./lib下にて
layer.zipの部分は、「1. Lambda Package」で作成したmomentoのパッケージファイルの相対pathを指定します。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as path from 'path';
export class LambdaLayerStack extends cdk.Stack {
public readonly layer: lambda.LayerVersion;
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const commonLayerName = `demo-layer-momento`;
const commonLayer = new lambda.LayerVersion(this, commonLayerName, {
layerVersionName: commonLayerName,
code: lambda.AssetCode.fromAsset(path.join(__dirname, '../src/lambda/layers/layer.zip')), // momento パッケージを圧縮したファイルを指定
compatibleRuntimes: [lambda.Runtime.PYTHON_3_10],
});
// rtn
this.layer = commonLayer;
}
}
続いてLambdaFunctionを作成するCDKになります。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as path from 'path';
export class LambdaFuncStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const region = this.region;
const accountId = this.account;
const funcName = 'demo-func-hello-world';
const layerArn = `arn:aws:lambda:${region}:${accountId}:layer:demo-layer-momento:1`;
const momentoCacheName = 'test-api-cache'
const func = new lambda.Function(this, funcName, {
functionName: funcName,
runtime: lambda.Runtime.PYTHON_3_10,
code: lambda.Code.fromAsset(path.join(__dirname, '../src/lambda/hello_world')),
handler: 'lambda_function.lambda_handler',
environment: {
MOMENTO_API_KEY: 'xXxXxX',
MOMENTO_CACHE_NAME: momentoCacheName,
APISPORTS_API_KEY: 'xXxXxX'
},
timeout: cdk.Duration.seconds(120),
});
func.addLayers(lambda.LayerVersion.fromLayerVersionArn(this, `LambdaLayer`, layerArn));
}
}
次にLambdaのソースファイルとなるlambda_function.pyを作成したいと思います。
今回はシンプルにMomentoクライアント認証したのち、キャッシュにキーと値をMomento Cacheへセットするだけのシンプルなものになります。
import json
import os
from datetime import timedelta
import boto3
import logging
from momento import CacheClient, Configurations, CredentialProvider
from momento.responses import CacheGet, CacheSet, CreateCache, ListCaches, CacheIncrement
MOMENTO_API_KEY = os.getenv('MOMENTO_API_KEY', 'xXxXxXxXxXxXxXxXxX')
MOMENTO_CACHE_NAME = os.getenv('MOMENTO_CACHE_NAME', 'test-cache-name')
logger = logging.getLogger()
logger.setLevel("INFO")
def lambda_handler(event, context):
client = create_cache_client()
client.set(MOMENTO_CACHE_NAME, "test-key", "test-value")
res = client.get(MOMENTO_CACHE_NAME, "test-key")
logger.info("Result: {}".format(res))
return {
'statusCode': 200,
'body': json.dumps(res)
}
def create_cache_client():
cache_client = CacheClient(
configuration=Configurations.Laptop.v1(),
credential_provider=CredentialProvider.from_environment_variable("MOMENTO_API_KEY"),
default_ttl=timedelta(seconds=600),
)
return cache_client
最後にデプロイコマンドを実行します。
以下のコマンドを実行して、CDKデプロイを実施します。
cdk synth
cdk deploy
最後にLambdaのテストをします。
以下のようにキャッシュのキーに関連した値を取得することができます。
終わりに
今回は、Momentoと呼ばれるSaaSのサービスについて触ってみました。
ほかにも有用なSaaSサービスがあったらそれにも触ってみたいと思います。