使用Lambda(Node.js)在ElastiCache for Memcached上运行

elasticache.png

AWS云开发工具包 (AWS CDK)

创建VPC,并将ElastiCache和Lambda部署在同一子网中。将ElastiCache的配置终端节点设置为Lambda的环境变量。请从以下链接中选择适当的节点来设置cacheNodeType。

    サポートされているノードの種類 – Amazon ElastiCache

为了从VPC Lambda访问ElastiCache,需要创建安全组的入站规则。

import { Construct } from 'constructs';
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as elasticache from 'aws-cdk-lib/aws-elasticache';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as lambdaNodeJs from 'aws-cdk-lib/aws-lambda-nodejs';

export class SampleStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
        super(scope, id, props);

        // VPC
        const vpc = this.createVpc();
        const securityGroup = this.createVpcSecurityGroup(vpc);

        // ElastiCache
        const memcache = this.createElasticache(vpc, securityGroup);
        const memcachedConfigEndpoint = `${memcache.attrConfigurationEndpointAddress}:${memcache.attrConfigurationEndpointPort}`;

        // VPC Lambda
        this.createFunc(vpc, memcachedConfigEndpoint);
    }

    /**
     * @description VPCを作成する
     * {@link Vpc | https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.Vpc.html}
     */
    private createVpc(): ec2.IVpc {
        return new ec2.Vpc(this, 'Vpc', {
            ipAddresses: ec2.IpAddresses.cidr('192.168.0.0/16'),
            subnetConfiguration: [
                {
                    name: `vpc-public`,
                    cidrMask: 24,
                    subnetType: ec2.SubnetType.PUBLIC,
                },
                {
                    cidrMask: 24,
                    name: `vpc-private`,
                    subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
                },
            ],
        });
    }

    /**
     * {@link SecurityGroup | https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.SecurityGroup.html}
     */
    private createVpcSecurityGroup(vpc: ec2.IVpc): ec2.SecurityGroup {
        return new ec2.SecurityGroup(this, 'VpcSecurityGroup', { vpc });
    }

    /**
     * @description ElastiCache for Memcachedを作成する
     * {@link Amazon ElastiCache for Memcached | https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/mem-ug/WhatIs.html}
     * {@link CfnSubnetGroup | https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_elasticache.CfnSubnetGroup.html}
     * {@link CfnCacheCluster | https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_elasticache.CfnCacheCluster.html}
     */
    private createElasticache(vpc: ec2.IVpc, securityGroup: ec2.SecurityGroup): elasticache.CfnCacheCluster {
        const subnetGroup = new elasticache.CfnSubnetGroup(this, 'SubnetGroup', {
            description: 'private subnet',
            subnetIds: vpc.selectSubnets({ subnetType: ec2.SubnetType.PRIVATE_ISOLATED }).subnetIds,
        });

        const cluster = new elasticache.CfnCacheCluster(this, 'ElastiCache', {
            engine: 'memcached',
            cacheNodeType: 'cache.r6g.large',
            numCacheNodes: 1,
            cacheSubnetGroupName: subnetGroup.ref,
            vpcSecurityGroupIds: [securityGroup.securityGroupId], // vpcSecurityGroupIds,cacheSecurityGroupNamesのいずれかが必須
        });

        // インバウンドルールの追加
        const port = ec2.Port.tcp(cluster.port ?? 11211);
        securityGroup.addIngressRule(ec2.Peer.anyIpv4(), port);

        return cluster;
    }

    /**
     * @description Lambdaの作成
     * {@link NodejsFunction | https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html}
     */
    private createFunc(vpc: ec2.IVpc, memcachedConfigEndpoint: string): lambdaNodeJs.NodejsFunction {
        return new lambdaNodeJs.NodejsFunction(this, 'SampleFunc', {
            entry: 'src/lambda/sample/index.ts',
            handler: 'handler',
            runtime: lambda.Runtime.NODEJS_18_X,
            timeout: cdk.Duration.minutes(5),
            environment: {
                MEMCACHED_CONFIG_ENDPOINT: memcachedConfigEndpoint,
            },
            vpc,
            vpcSubnets: vpc.selectSubnets({ subnetType: ec2.SubnetType.PRIVATE_ISOLATED }),
        });
    }
}

Lambda(拉姆达)

在这里,我们将使用一个名为”Memcache Plus”的库作为memcached客户端。
这个库具有一个名为”autodiscover”的功能,可以从ElastiCache的配置端点获取端点信息。

% npm install memcache-plus aws-lambda
% npm install --save-dev @types/aws-lambda esbuild@0
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
import MemcachePlus = require('memcache-plus');

export async function handler(event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> {
    const configEndpoint: string = process.env.MEMCACHED_CONFIG_ENDPOINT ?? '';

    const client = new MemcachePlus({
        hosts: [configEndpoint],
        autodiscover: true,
    });
    const ttl = 86400 * 30; // キャッシュ期間。単位秒。

    const key = 'key';
    const input = Math.floor(Math.random() * 1000);

    // データをキャッシュする。keyは250バイトまで。
    await client.set(key, input, ttl);

    // キャッシュしたデータを取得する。存在しない場合はnullを返却する。
    const output = await client.get(key);

    if (input === output) {
        console.debug(`memcachedから取得した値: ${output}`);
        return {
            statusCode: 200,
            body: output,
        };
    } else {
        console.error(`期待値: ${input}, 実際: ${output}`);
        return {
            statusCode: 500,
            body: `期待値: ${input}, 実際: ${output}`
        };
    }
}
declare module 'memcache-plus' {
    interface MemcacheOptions {
        autodiscover?: boolean;
        backoffLimit?: number;
        bufferBeforeError?: number;
        disabled?: boolean;
        hosts?: string | string[];
        maxValueSize?: number;
        queue?: boolean;
        netTimeout?: number;
        reconnect?: boolean;
    }

    class MemcacheClient {
        constructor(param: string | string[] | MemcacheOptions);
        get(key: string): Promise<any>;
        set(key: string, value: any, lifetime?: number): Promise<any>;
        // 必要に応じて他のメソッドの型定義を追加
    }

    export = MemcacheClient;
}

考试

test/sample.test.tstest/sample.test.ts

在测试文件 `test/sample.test.ts` 中,

“`typescript
import * as cdk from ‘aws-cdk-lib’;
import { Match, Template } from ‘aws-cdk-lib/assertions’;
import { SampleStack } from ‘../lib/sample-stack’;

test(‘SecurityGroup’, () => {
const app = new cdk.App();
const stack = new SampleStack(app, ‘SampleStack’);
const template = Template.fromStack(stack);

// Security Group
template.hasResourceProperties(‘AWS::EC2::SecurityGroup’, {
VpcId: Match.anyValue(),
SecurityGroupIngress: [{
“CidrIp”: “0.0.0.0/0”,
“Description”: “from 0.0.0.0/0:11211”,
“FromPort”: 11211,
“IpProtocol”: “tcp”,
“ToPort”: 11211
}]
});
});

test(‘ElastiCache’, () => {
const app = new cdk.App();
const stack = new SampleStack(app, ‘SampleStack’);
const template = Template.fromStack(stack);

// Subnet Group
template.resourceCountIs(‘AWS::ElastiCache::SubnetGroup’, 1);
template.hasResourceProperties(‘AWS::ElastiCache::SubnetGroup’, {
SubnetIds: Match.anyValue(),
Description: ‘private subnet’,
});

// Cache Cluster
template.resourceCountIs(‘AWS::ElastiCache::CacheCluster’, 1);
template.hasResourceProperties(‘AWS::ElastiCache::CacheCluster’, {
Engine: ‘memcached’,
CacheNodeType: ‘cache.r6g.large’,
NumCacheNodes: 1,
CacheSubnetGroupName: Match.anyValue(),
VpcSecurityGroupIds: Match.anyValue(),
});
});

test(‘Lambda’, () => {
const app = new cdk.App();
const stack = new SampleStack(app, ‘SampleStack’);
const template = Template.fromStack(stack);

// Lambda
template.resourceCountIs(‘AWS::Lambda::Function’, 1);
template.hasResourceProperties(‘AWS::Lambda::Function’, {
Runtime: ‘nodejs18.x’,
Timeout: 300,
VpcConfig: Match.anyValue(),
});
});
“`

将测试文件 `test/sample.test.ts` 中的内容进行了汉语表达。

错误 (wù)

错误:spawnSync docker ENOENT

通过安装esbuild来解决该问题。

$ npm install --save-dev esbuild@0
    @aws-cdk/aws-lambda-nodejs module · AWS CDK

错误 TS2688:找不到类型定义文件“babel__generator”。

有时通过删除 node_modules 并重新执行 npm install 可以解决该问题。

自动发现失败。错误:连接超时 192.168.3.236:11211。

如果安全组没有添加入站规则,可能会发生此错误。TCP的入站和出站流量都需要允许。出站规则默认情况下被全部允许,所以需要设置入站规则。如果要手动设置,可以按照以下方式进行设置。

スクリーンショット 2023-08-11 13.03.13.png

只需要一种选择:在中文中改述以下内容。

    • AWS CDK

AWS CDK Intro Workshop
API Reference · AWS CDK

ElastiCache

Amazon ElastiCache for Memcached とは – Amazon ElastiCache

Memcached Client

Memcache Plus
victorquinn/memcache-plus: Memcache Plus – Better memcache for node

广告
将在 10 秒后关闭
bannerAds