如何在亚马逊云科技上大幅降低无服务器网页应用冷启动时间(上篇)

server/2025/1/19 1:55:33/

背景

我们在云端搭建无服务器(serverless开发架构时,经常会被冷启动(cold start)带来的应用延迟所困扰。冷启动是指当无服务器资源在一段时间内未被调用,或需要扩展以处理新请求时,系统需要初始化一个新的执行环境,这个过程会引入额外的延迟。通常造成冷启动的原因是无服务器资源初始化函数所花费的时间,这里包括加载函数代码、启动运行环境以及初始化函数代码的过程。

这种冷启动给开发者的日常开发带来了诸多的不便,最主要的就是应用访问延迟带来用户体验差,函数响应时间可能从从平时的毫秒级增加到数百毫秒甚至数秒。其次,由于冷启动的时间是不确定的并且难以控制,造成大规模系统中的应用程序的性能可能会出现波动,特别是在对响应时间敏感的应用。

在本系列文章中,我将和大家分享如何在消除电商场景下的无服务器应用架构的冷启动时间。同时学习如何将本地Java应用,进行无服务器云原生改造迁移到亚马逊云科技的Lambda上。在本系列上篇中我将带大家搭建一个本地话电商场景应用。电商场景下的无服务器网页应用架构如下:

方案所需知识

1. Lambda:无服务器计算的核心

AWS Lambda 是一种无服务器计算服务,可让开发者无需管理基础设施,按需运行代码。Lambda 的执行模型基于事件触发,支持多种编程语言,并与 AWS 服务无缝集成。开发者只需专注于业务逻辑,其余资源管理、扩展和高可用性由亚马逊云科技自动处理。

优势开发者可以显著降低运维成本,实现更高的开发效率,同时按实际运行时间付费,经济高效。

2. Lambda Web Adapter:简化传统 Web 应用迁移

Lambda Web Adapter 是 亚马逊云科技提供的官方开源工具,用于帮助开发者将传统的 Java Web 应用快速迁移到无服务器架构。通过适配器,开发者可以继续使用现有的 Web 框架(如 Spring Boot、Javalin 等),无需对代码进行大规模改动。

优势:Web Adapter桥接了传统应用和无服务器架构之间的差距,让开发者轻松实现应用现代化,同时保留已有的技术栈。

3. Amazon Lambda SnapStart:显著优化冷启动性能

Amazon Lambda SnapStart 是 AWS 提供的功能,用于优化函数的启动性能。Lambda 会对已初始化的[执行环境]的内存和磁盘状态创建Firecracker microVM 快照、加密该快照并对其进行缓存以实现低延迟访问。在实际调用或者无服务器资源纵向扩展时快速加载快照,从而显著减少冷启动延迟,尤其对 Java 等需要较长初始化时间的语言效果显著。

优势:SnapStart 能将冷启动时间减少高达 90%,使 Java 应用在无服务器架构中具备更快的响应速度,为延迟敏感型应用提供了理想解决方案。

本文适用人群

软件开发工程师(Java)、DevOps、亚马逊云科技运维、云原生开发者等。

本实践包括的内容 

1. 了解亚马逊云科技上的云原生无服务器Serverless架构设计,和亚马逊云科技无服务器服务(如Lambda、API Gateway、Aurora Serverless、OpenSearch Serverless等)

2. 使用Lambda web apdater工具将电商场景下的传统springboot应用,从本地迁移到Lambda,实现Java应用云原生现代化改造。

3. 通过Lambda Snapshot功能降低无服务器开发服务的冷启动时间(启动性能提升10倍以上)。

项目实操步骤

1. 初始化云端开发环境

本项目将运行在Ubuntu系统的EC2中,在系统中我们将安装GitHub开源项目Code Server在网页段进行项目开发

1)首先我们登录控制台进入EC2服务主页。

2)在控制台并选择左侧“实例“ ,将目前处于”已停止“的实例“启动”,等待启动完成。

3)在控制台中进入“Cloudformation”

4)创建一个名为“CloudlabCampaign”的堆栈(第一个),并点击名称进入。堆栈YAML配置脚本如下;

AWSTemplateFormatVersion: 2010-09-09
Description: Lambda Web Adpater workshop environment.
Parameters:InstanceVolumeSize:Type: NumberDescription: The volume size in GBDefault: 30InstanceType:Description: Type of EC2 instance to launchType: StringDefault: c6i.xlargeAllowedValues: [c6i.large, c6i.xlarge, c6i.2xlarge, c6i.4xlarge,m6a.large, m6a.xlarge, m6a.2xlarge, m6a.4xlarge,t3.nano, t3.micro, t3.small, t3.medium, t3.large, t3.xlarge, t3.2xlarge,]HomeFolder:Type: StringDescription: The home folder in the VSCodeInstanceDefault: /WorkshopDevServerBasePath:Type: StringDescription: The base path for the application to be added to nginx sites-available list for code-serverDefault: appDevServerPort:Type: NumberDescription: The port for the DevServerDefault: 8081
Metadata:AWS::CloudFormation::Interface:ParameterGroups:- Label:default: Instance ConfigurationParameters:- InstanceVolumeSize- Label:default: Code Server ConfigurationParameters:- HomeFolder- DevServerBasePath- DevServerPortParameterLabels:InstanceVolumeSize:default: Attached volume sizeHomeFolder:default: Folder to open in code server when launchingDevServerBasePath:default: BasePath where the application runsDevServerPort:default: Port where the application runs
Mappings:Subnets:VPC:CIDR: 10.0.0.0/16PublicOne:CIDR: 10.0.1.0/24PublicTwo:CIDR: 10.0.2.0/24PrivateOne:CIDR: 10.0.3.0/24PrivateTwo:CIDR: 10.0.4.0/24# aws ec2 describe-managed-prefix-lists  --region <REGION> | jq -r '.PrefixLists[] | select (.PrefixListName == "com.amazonaws.global.cloudfront.origin-facing") | .PrefixListId'AWSRegions2PrefixListID:ap-northeast-1:PrefixList: pl-58a04531ap-northeast-2:PrefixList: pl-22a6434bap-south-1:PrefixList: pl-9aa247f3ap-southeast-1:PrefixList: pl-31a34658ap-southeast-2:PrefixList: pl-b8a742d1ca-central-1:PrefixList: pl-38a64351eu-central-1:PrefixList: pl-a3a144caeu-north-1:PrefixList: pl-fab65393eu-west-1:PrefixList: pl-4fa04526eu-west-2:PrefixList: pl-93a247faeu-west-3:PrefixList: pl-75b1541csa-east-1:PrefixList: pl-5da64334us-east-1:PrefixList: pl-3b927c52us-east-2:PrefixList: pl-b6a144dfus-west-1:PrefixList: pl-4ea04527us-west-2:PrefixList: pl-82a045ebResources:TrialUseOnlyRoleManagedPolicy:Type: AWS::IAM::ManagedPolicyProperties:ManagedPolicyName: TrialUseOnlyRoleManagedPolicyPath: "/"PolicyDocument: '{"Version":"2012-10-17","Statement":[{"Sid":"VisualEditor1","Effect":"Allow","Action":["xray:*","cloudformation:*","cloudwatch:*","ec2:*","s3:*","lambda:*","rds:*","apigateway:*","elasticache:*","ssm:*","ssm:StartSession","ssm-guiconnect:GetConnection","ssm-guiconnect:CancelConnection","ssm-guiconnect:StartConnection","iam:CreateInstanceProfile","iam:DeleteInstanceProfile","iam:PassRole","iam:RemoveRoleFromInstanceProfile","iam:AddRoleToInstanceProfile"],"Resource":"*"}]}'DeletionPolicy: DeleteTrialUseOnlyRole:Type: AWS::IAM::RoleProperties:RoleName: TrialUseOnly-ContentGeneratedByGenAIDoesNotRepresentViewsOfAWSAssumeRolePolicyDocument:Statement:- Sid: 'AllowCloudlabDelegateAssumeThisRole'Effect: AllowPrincipal:AWS:- 'arn:aws:iam::976193244280:root'Action:- 'sts:AssumeRole'Path: "/"ManagedPolicyArns:- Ref: TrialUseOnlyRoleManagedPolicyDeletionPolicy: Delete########### VPC Resources ###########VPC:Type: AWS::EC2::VPCProperties:CidrBlock: !FindInMap [Subnets, VPC, CIDR]EnableDnsSupport: trueEnableDnsHostnames: trueTags:- Key: NameValue: !Sub ${AWS::StackName}-VPCInternetGateway:Type: AWS::EC2::InternetGatewayGatewayAttachment:Type: AWS::EC2::VPCGatewayAttachmentProperties:VpcId: !Ref VPCInternetGatewayId: !Ref InternetGatewayPublicSubnetOne:Type: AWS::EC2::SubnetProperties:CidrBlock: !FindInMap [Subnets, PublicOne, CIDR]VpcId: !Ref VPCMapPublicIpOnLaunch: trueAvailabilityZone: !Select [0, !GetAZs '']PublicOneRouteTable:Type: AWS::EC2::RouteTableProperties:VpcId: !Ref VPCPublicOneRoute:Type: AWS::EC2::RouteDependsOn: GatewayAttachmentProperties:RouteTableId: !Ref PublicOneRouteTableDestinationCidrBlock: 0.0.0.0/0GatewayId: !Ref InternetGatewayPublicOneRouteTableAssoc:Type: AWS::EC2::SubnetRouteTableAssociationProperties:RouteTableId: !Ref PublicOneRouteTableSubnetId: !Ref PublicSubnetOnePublicSubnetTwo:Type: AWS::EC2::SubnetProperties:CidrBlock: !FindInMap [Subnets, PublicTwo, CIDR]VpcId: !Ref VPCMapPublicIpOnLaunch: trueAvailabilityZone: !Select [1, !GetAZs '']PublicTwoRouteTable:Type: AWS::EC2::RouteTableProperties:VpcId: !Ref VPCPublicTwoRoute:Type: AWS::EC2::RouteDependsOn: GatewayAttachmentProperties:RouteTableId: !Ref PublicTwoRouteTableDestinationCidrBlock: 0.0.0.0/0GatewayId: !Ref InternetGatewayPublicTwoRouteTableAssoc:Type: AWS::EC2::SubnetRouteTableAssociationProperties:RouteTableId: !Ref PublicTwoRouteTableSubnetId: !Ref PublicSubnetTwoPrivateSubnetOne:Type: AWS::EC2::SubnetProperties:CidrBlock: !FindInMap [Subnets, PrivateOne, CIDR]VpcId: !Ref VPCMapPublicIpOnLaunch: trueAvailabilityZone: !Select [0, !GetAZs '']PrivateSubnetTwo:Type: AWS::EC2::SubnetProperties:CidrBlock: !FindInMap [Subnets, PrivateTwo, CIDR]VpcId: !Ref VPCMapPublicIpOnLaunch: trueAvailabilityZone: !Select [1, !GetAZs '']ApplicationSecurityGroup:Type: AWS::EC2::SecurityGroupProperties:GroupDescription: SG for Developer Machine - only allow CloudFront ingressSecurityGroupIngress:- Description: Allow HTTP from com.amazonaws.global.cloudfront.origin-facingIpProtocol: tcpFromPort: 80ToPort: 80SourcePrefixListId:  !FindInMap [AWSRegions2PrefixListID, !Ref 'AWS::Region', PrefixList]SecurityGroupEgress:- Description: Allow all outbound trafficIpProtocol: -1CidrIp: 0.0.0.0/0VpcId: !Ref VPCEC2SecurityGroup:Type: AWS::EC2::SecurityGroupProperties:GroupDescription: SG for Developer Machine - only allow traffic from specific ELBSecurityGroupIngress:- Description: Allow HTTP from ELBIpProtocol: tcpFromPort: 80ToPort: 80SourceSecurityGroupId: !Ref ApplicationSecurityGroupSecurityGroupEgress:- Description: Allow all outbound trafficIpProtocol: -1CidrIp: 0.0.0.0/0VpcId: !Ref VPCPrivateSubnetOneParameter:Type: AWS::SSM::ParameterProperties:Name: !Sub /litemall/prod/vpc/private-subnet-oneType: StringValue: !Ref PrivateSubnetOneDescription: Private Subnet One's IDPrivateSubnetTwoParameter:Type: AWS::SSM::ParameterProperties:Name: !Sub /litemall/prod/vpc/private-subnet-twoType: StringValue: !Ref PrivateSubnetTwoDescription: Private Subnet Two's IDApplicationSecurityGroupParameter:Type: AWS::SSM::ParameterProperties:Name: !Sub /litemall/prod/vpc/application-security-groupType: StringValue: !Ref ApplicationSecurityGroupDescription: Application Security Group ID########### SSM Resources ###########SSMLogBucket:Type: AWS::S3::BucketMetadata:cfn_nag:rules_to_suppress:- id: W35reason: Access logs aren't needed for this bucketDeletionPolicy: DeleteProperties:AccessControl: PrivateBucketEncryption:ServerSideEncryptionConfiguration:- ServerSideEncryptionByDefault:SSEAlgorithm: AES256PublicAccessBlockConfiguration:BlockPublicAcls: trueBlockPublicPolicy: trueIgnorePublicAcls: trueRestrictPublicBuckets: trueVSCodeInstanceSSMDoc:Type: AWS::SSM::DocumentProperties:DocumentType: CommandContent:schemaVersion: '2.2'description: Bootstrap VSCode code-server instanceparameters:architecture:type: Stringdefault: amd64description: Instance architecture typeallowedValues:- arm64- amd64ubuntuVersion:type: Stringdefault: jammyallowedValues:- focal- bionic- jammynodeVersion:type: Stringdefault: node_20.xallowedValues:- node_21.x- node_20.x- node_19.xdotNetVersion:type: Stringdefault: dotnet-sdk-8.0allowedValues:- dotnet-sdk-8.0- dotnet-sdk-7.0- dotnet-sdk-8.0mainSteps:- action: aws:runShellScriptname: InstallAWSCLIinputs:runCommand:- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y curl unzip- curl -fsSL https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip -o /tmp/aws-cli.zip- unzip -q -d /tmp /tmp/aws-cli.zip- sudo /tmp/aws/install- rm -rf /tmp/aws- aws --version- action: aws:runShellScriptname: InstallDockerinputs:runCommand:- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg- echo "deb [signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu {{ ubuntuVersion }} stable" >> /etc/apt/sources.list.d/docker.list- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce docker-ce-cli containerd.io- usermod -aG docker ubuntu- docker --version- action: aws:runShellScriptname: InstallGitinputs:runCommand:- add-apt-repository ppa:git-core/ppa- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y software-properties-common- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y git- sudo -u ubuntu git config --global user.email "participant@workshops.aws"- sudo -u ubuntu git config --global user.name "Workshop Participant"- sudo -u ubuntu git config --global init.defaultBranch "main"- git --version- action: aws:runShellScriptname: InstallNodeinputs:runCommand:- curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | gpg --dearmor -o /usr/share/keyrings/nodesource-keyring.gpg- echo "deb [arch={{ architecture }} signed-by=/usr/share/keyrings/nodesource-keyring.gpg] https://deb.nodesource.com/{{ nodeVersion }} {{ ubuntuVersion }} main" >> /etc/apt/sources.list.d/nodesource.list- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs- action: aws:runShellScriptname: InstallPythoninputs:runCommand:- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y python3-pip python3.10-venv python3-boto3 python3-pytest- echo 'alias pytest=pytest-3' >> /home/ubuntu/.bashrc- python3 --version- pip3 --version- action: aws:runShellScriptname: UpdateProfileinputs:runCommand:- '#!/bin/bash'- echo LANG=en_US.utf-8 >> /etc/environment- echo LC_ALL=en_US.UTF-8 >> /etc/environment- echo 'PATH=$PATH:/home/ubuntu/.local/bin' >> /home/ubuntu/.bashrc- echo 'export PATH' >> /home/ubuntu/.bashrc- !Sub echo 'export AWS_REGION=${AWS::Region}' >> /home/ubuntu/.bashrc- !Sub echo 'export AWS_ACCOUNTID=${AWS::AccountId}' >> /home/ubuntu/.bashrc- echo 'export NEXT_TELEMETRY_DISABLED=1' >> /home/ubuntu/.bashrc- action: aws:runShellScriptname: ConfigureCodeServerinputs:runCommand:- '#!/bin/bash'- export HOME=/home/ubuntu- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y nginx- curl -fsSL https://code-server.dev/install.sh | sh- sudo systemctl enable --now code-server@ubuntu- !Sub |sudo tee /etc/nginx/sites-available/code-server <<EOFserver {listen 80;listen [::]:80;server_name ${CloudFrontDistribution.DomainName};location / {proxy_pass http://localhost:8080/;proxy_set_header Host \$host;proxy_set_header Upgrade \$http_upgrade;proxy_set_header Connection upgrade;proxy_set_header Accept-Encoding gzip;}location /${DevServerBasePath} {proxy_pass http://localhost:${DevServerPort}/${DevServerBasePath};proxy_set_header Host \$host;proxy_set_header Upgrade \$http_upgrade;proxy_set_header Connection upgrade;proxy_set_header Accept-Encoding gzip;}}EOF- |sudo tee /home/ubuntu/.config/code-server/config.yaml <<EOFcert: falseauth: passwordhashed-password: "$(echo -n $(aws sts get-caller-identity --query "Account" --output text) | sudo npx argon2-cli -e)"EOF- sudo -u ubuntu --login mkdir -p /home/ubuntu/.local/share/code-server/User/- sudo -u ubuntu --login touch /home/ubuntu/.local/share/code-server/User/settings.json- !Sub |sudo tee /home/ubuntu/.local/share/code-server/User/settings.json <<EOF{"extensions.autoUpdate": false,"extensions.autoCheckUpdates": false,"terminal.integrated.cwd": "${HomeFolder}","telemetry.telemetryLevel": "off","security.workspace.trust.startupPrompt": "never","security.workspace.trust.enabled": false,"security.workspace.trust.banner": "never","security.workspace.trust.emptyWindow": false,"editor.tabSize": 2,"python.testing.pytestEnabled": true,"auto-run-command.rules": [{"command": "workbench.action.terminal.new"}]}EOF- sudo systemctl restart code-server@ubuntu- sudo ln -s ../sites-available/code-server /etc/nginx/sites-enabled/code-server- sudo systemctl restart nginx- sudo -u ubuntu --login code-server --install-extension AmazonWebServices.amazon-q-vscode --force- sudo -u ubuntu --login code-server --install-extension synedra.auto-run-command --force- sudo -u ubuntu --login code-server --install-extension mtxr.sqltools --force- sudo -u ubuntu --login code-server --install-extension mtxr.sqltools-driver-mysql --force- sudo -u ubuntu --login code-server --install-extension vmware.vscode-boot-dev-pack --force- sudo chown ubuntu:ubuntu /home/ubuntu -R- action: aws:runShellScriptname: InstallCDKinputs:runCommand:- npm install -g aws-cdk- cdk --version- action: aws:runShellScriptname: InstallJavaToolsinputs:runCommand:- wget -O - https://apt.corretto.aws/corretto.key | sudo gpg --dearmor -o /usr/share/keyrings/corretto-keyring.gpg- echo "deb [signed-by=/usr/share/keyrings/corretto-keyring.gpg] https://apt.corretto.aws stable main" | sudo tee /etc/apt/sources.list.d/corretto.list- sudo apt-get update && sudo apt-get install -y java-17-amazon-corretto-jdk && sudo apt-get install -y java-1.8.0-amazon-corretto-jdk- sudo apt-get install -y maven- mvn -version- action: aws:runShellScriptname: InstallAWSSamCliinputs:runCommand:- wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip- unzip aws-sam-cli-linux-x86_64.zip -d sam-installation- sudo ./sam-installation/install- aws --version- rm aws-sam-cli-linux-x86_64.zip && rm -rf sam-installation- action: aws:runShellScriptname: InstallToolsinputs:runCommand:- sudo apt install -y mysql-client-core-8.0 redis-tools jqVSCodeInstanceSSMAssociation:Type: AWS::SSM::AssociationProperties:Name: !Ref VSCodeInstanceSSMDocOutputLocation:S3Location:OutputS3BucketName: !Ref SSMLogBucketOutputS3KeyPrefix: bootstrapTargets:- Key: tag:SSMBootstrapValues: [True]### Empty S3 bucket resources ###EmptyS3BucketExecutionRole:Type: AWS::IAM::RoleProperties:AssumeRolePolicyDocument:Version: 2012-10-17Statement:- Effect: AllowPrincipal:Service: lambda.amazonaws.comAction: sts:AssumeRoleManagedPolicyArns:- !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRolePolicies:- PolicyName: !Sub EmptyS3BucketPolicy-${AWS::Region}PolicyDocument:Version: 2012-10-17Statement:- Effect: AllowAction:- s3:ListBucket- s3:DeleteObjectResource: '*'EmptyS3Bucket:Type: AWS::Lambda::FunctionMetadata:cfn_nag:rules_to_suppress:- id: W58reason: EmptyS3BucketExecutionRole has the AWSLambdaBasicExecutionRole managed policy attached, allowing writing to CloudWatch logs- id: W89reason: Bootstrap function does not need the scaffolding of a VPC or provisioned concurrency- id: W92reason: Bootstrap function does not need provisioned concurrencyProperties:Description: Empty S3 bucket CloudFormation custom resourceHandler: index.lambda_handlerRole:Fn::GetAtt:- EmptyS3BucketExecutionRole- ArnRuntime: python3.11MemorySize: 1024Timeout: 400Code:ZipFile: |import boto3import cfnresponseimport logginglogger = logging.getLogger(__name__)logger.setLevel(logging.INFO)def lambda_handler(event, context):logger.info('event: {}'.format(event))logger.info('context: {}'.format(context))if event['RequestType'] == 'Delete':try:AssetsBucketName = (event['ResourceProperties']['S3Bucket'])s3 = boto3.resource('s3')logger.info('S3 Object initialized')bucket = s3.Bucket(AssetsBucketName)logger.info('S3 bucket: ' + AssetsBucketName)bucket.objects.all().delete()cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData={}, reason='S3 bucket emptied: ' + AssetsBucketName )except Exception as e:logger.error(e, exc_info=True)cfnresponse.send(event, context, cfnresponse.FAILED, responseData={}, reason=str(e))else:cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData={}, reason='No action to take')EmptyS3BucketLogGroup:Metadata:cfn_nag:rules_to_suppress:- id: W84reason: KMS Key not required for encrypting this non sensitive dataType: AWS::Logs::LogGroupDeletionPolicy: DeleteUpdateReplacePolicy: DeleteProperties:LogGroupName: !Sub /aws/lambda/${EmptyS3Bucket}RetentionInDays: 7EmptyS3BucketCustomResource:Type: Custom::EmptyS3BucketProperties:ServiceToken: !GetAtt EmptyS3Bucket.ArnS3Bucket: !Ref SSMLogBucket########### EC2 Resources ###########VSCodeInstanceRole:Metadata:cfn_nag:rules_to_suppress:- id: W11reason: CodeWhisperer requires '*' as a resource, reference https://docs.aws.amazon.com/codewhisperer/latest/userguide/cloud9-setup.html#codewhisperer-IAM-policiesType: AWS::IAM::RoleProperties:AssumeRolePolicyDocument:Version: 2012-10-17Statement:- Effect: AllowPrincipal:Service:- ec2.amazonaws.com- ssm.amazonaws.comAction:- 'sts:AssumeRole'ManagedPolicyArns:- !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccessPolicies:- PolicyName: !Sub CDKAssumeRolePolicy-${AWS::Region}PolicyDocument:Version: 2012-10-17Statement:- Effect: AllowAction:- sts:AssumeRoleResource:- !Sub arn:${AWS::Partition}:iam::*:role/cdk-*- PolicyName: !Sub Codewhisperer-${AWS::Region}PolicyDocument:Version: 2012-10-17Statement:- Effect: AllowAction:- codewhisperer:GenerateRecommendationsResource: '*'VSCodeInstanceProfile:Type: AWS::IAM::InstanceProfileProperties:Roles:- !Ref VSCodeInstanceRoleVSCodeInstanceEC2Instance:Type: AWS::EC2::InstanceProperties:BlockDeviceMappings:- Ebs:VolumeSize: !Ref InstanceVolumeSizeVolumeType: gp3DeleteOnTermination: trueEncrypted: trueDeviceName: /dev/sda1Monitoring: trueSubnetId: !Ref PublicSubnetOneImageId: >-{{resolve:ssm:/aws/service/canonical/ubuntu/server/22.04/stable/current/amd64/hvm/ebs-gp2/ami-id}}InstanceType: !Ref InstanceTypeSecurityGroupIds:- !Ref EC2SecurityGroupIamInstanceProfile: !Ref VSCodeInstanceProfileUserData:Fn::Base64: !Sub |#cloud-confighostname: devruncmd:- mkdir -p ${HomeFolder} && chown ubuntu:ubuntu ${HomeFolder}Tags:- Key: SSMBootstrapValue: TrueVSCodeLoadBalancer:Type: AWS::ElasticLoadBalancingV2::LoadBalancerProperties:Scheme: internet-facingSecurityGroups:- !Ref ApplicationSecurityGroupSubnets:- !Ref PublicSubnetOne- !Ref PublicSubnetTwoType: applicationVSCodeTargetGroup:Type: AWS::ElasticLoadBalancingV2::TargetGroupProperties:Name: vs-code-tgPort: 80Protocol: HTTPTargetType: instanceVpcId: !Ref VPCTargets:- Id: !Ref VSCodeInstanceEC2InstancePort: 80HealthCheckPath: /HealthyThresholdCount: 2UnhealthyThresholdCount: 2HealthCheckTimeoutSeconds: 5HealthCheckIntervalSeconds: 30Matcher:HttpCode: 200-399VSCodeListener:Type: AWS::ElasticLoadBalancingV2::ListenerProperties:DefaultActions:- Type: forwardTargetGroupArn: !Ref VSCodeTargetGroupLoadBalancerArn: !Ref VSCodeLoadBalancerPort: 80Protocol: HTTPLambdaEC2Role:Type: AWS::IAM::RoleProperties:#RoleName: LambdaEC2StartStopRoleDescription: IAM Role for Lambda to Start Stop EC2 instancesAssumeRolePolicyDocument:Version: 2012-10-17Statement:- Effect: AllowPrincipal:Service:- lambda.amazonaws.comAction:- sts:AssumeRolePath: /ManagedPolicyArns:- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRolePolicies:- PolicyName: LambdaEC2StartStopPolicyPolicyDocument:Version: 2012-10-17Statement:- Effect: AllowAction:- ec2:StartInstances- ec2:StopInstancesResource: arn:aws:ec2:*:*:instance/*- Effect: AllowAction:- ec2:DescribeInstances- ec2:DescribeTags- ec2:DescribeInstanceStatusResource: '*'CustomResourceLambda:Type: AWS::Lambda::FunctionProperties:FunctionName: EC2StopTriggerRuntime: python3.9Handler: index.lambda_handlerRole: !GetAtt LambdaEC2Role.ArnCode:ZipFile: |import boto3import loggingimport cfnresponseimport oslogger = logging.getLogger()logger.setLevel(logging.INFO)region = os.environ['AWS_REGION']ec2 = boto3.resource('ec2', region_name=region)def lambda_handler(event, context):filters = [{'Name': 'instance-state-name','Values': ['running']}]instances = ec2.instances.filter(Filters=filters)RunningInstances = [instance.id for instance in instances]print("Running Instances with AutoStop Tag : " + str(RunningInstances))if len(RunningInstances) > 0:for instance in instances:if instance.state['Name'] == 'running':print("Stopping Instance : " + instance.id)AutoStopping = ec2.instances.filter(InstanceIds=RunningInstances).stop()print("Stopped Instances : " + str(RunningInstances))cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData={}, reason='' )else:print("Instance not in Running state or AutoStop Tag not set...")cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData={}, reason='No action to take')Description: >-Auto Stop EC2 Instance (from tag : AutoStop)EC2StopTrigger:Type: Custom::EC2StopTriggerProperties:ServiceToken: !GetAtt CustomResourceLambda.ArnEC2InstanceId: !Ref VSCodeInstanceEC2InstanceDependsOn: VSCodeInstanceEC2Instance########### CloudFront Resources ###########VSCodeInstanceCachePolicy:Type: AWS::CloudFront::CachePolicyProperties:CachePolicyConfig:DefaultTTL: 86400MaxTTL: 31536000MinTTL: 1Name: !Join ['-', ['VSCodeServer', !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]]ParametersInCacheKeyAndForwardedToOrigin:CookiesConfig:CookieBehavior: allEnableAcceptEncodingGzip: FalseHeadersConfig:HeaderBehavior: whitelistHeaders:- Accept-Charset- Authorization- Origin- Accept- Referer- Host- Accept-Language- Accept-Encoding- Accept-DatetimeQueryStringsConfig:QueryStringBehavior: allCloudFrontDistribution:Type: AWS::CloudFront::DistributionProperties:DistributionConfig:Enabled: TrueHttpVersion: http2DefaultCacheBehavior:AllowedMethods:- GET- HEAD- OPTIONS- PUT- PATCH- POST- DELETECachePolicyId: !Ref VSCodeInstanceCachePolicyOriginRequestPolicyId: 216adef6-5c7f-47e4-b989-5492eafa07d3 # Managed-AllViewer - see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html#:~:text=When%20using%20AWS,47e4%2Db989%2D5492eafa07d3TargetOriginId: !Sub CloudFront-${AWS::StackName}ViewerProtocolPolicy: allow-allOrigins:- DomainName: !GetAtt VSCodeLoadBalancer.DNSNameId: !Sub CloudFront-${AWS::StackName}CustomOriginConfig:OriginProtocolPolicy: http-only########### Aurora MySQL Serverless Resources ###########DbSecurityGroup:Type: AWS::EC2::SecurityGroupProperties:GroupDescription: SG for Database - only allow ingress from Code ServerSecurityGroupIngress:- Description: Allow access from Code ServerIpProtocol: tcpFromPort: 3306ToPort: 3306SourceSecurityGroupId: !Ref EC2SecurityGroup- Description: Allow access from Code ServerIpProtocol: tcpFromPort: 3306ToPort: 3306SourceSecurityGroupId: !Ref ApplicationSecurityGroupSecurityGroupEgress:- Description: Allow all outbound trafficIpProtocol: -1CidrIp: 0.0.0.0/0VpcId: !Ref VPCDbSubnetGroup:Type: AWS::RDS::DBSubnetGroupProperties:DBSubnetGroupDescription: DBSubnetGroup for Aurora Serverless DBSubnetIds:- Ref: PrivateSubnetOne- Ref: PrivateSubnetTwoDBClusterParameterGroup:Type: AWS::RDS::DBClusterParameterGroupProperties:Description: "Litemall DB Cluster Parameter Group"Family: aurora-mysql8.0Parameters:character_set_server: utf8mb4collation_server: utf8mb4_unicode_ciDBMasterUsername:Type: AWS::SSM::ParameterProperties:Name: !Sub /litemall/prod/db/master-usernameType: StringValue: adminDescription: DB Master UsernameDBMasterPassword:Type: AWS::SSM::ParameterProperties:Name: !Sub /litemall/prod/db/master-passwordType: StringValue: !Sub LiteMall-${AWS::AccountId}Description: DB Master PasswordDatabaseCluster:Type: AWS::RDS::DBClusterDeletionPolicy: SnapshotProperties:Engine: aurora-mysqlEngineVersion: "8.0.mysql_aurora.3.05.2"DBClusterParameterGroupName: !Ref DBClusterParameterGroupMasterUsername: !GetAtt DBMasterUsername.ValueMasterUserPassword: !GetAtt DBMasterPassword.ValueServerlessV2ScalingConfiguration:MinCapacity: 0.5MaxCapacity: 16DBSubnetGroupName:Ref: DbSubnetGroupVpcSecurityGroupIds:- Ref: DbSecurityGroupDatabaseName: litemallDatabaseDefaultInstance:Type: AWS::RDS::DBInstanceProperties:Engine: aurora-mysqlDBInstanceClass: db.serverlessDBClusterIdentifier: !Ref DatabaseClusterMonitoringInterval: 0DBClusterEndpoint:Type: AWS::SSM::ParameterProperties:Name: !Sub /litemall/prod/db/cluster-endpointType: StringValue: !GetAtt DatabaseCluster.Endpoint.AddressDescription: DB Cluster Endpoint########### ElastiCache Redis Resources ###########RedisSecurityGroup:Type: AWS::EC2::SecurityGroupProperties:GroupDescription: SG for Redis - only allow ingress from Code ServerSecurityGroupIngress:- Description: Allow access from Code ServerIpProtocol: tcpFromPort: 6379ToPort: 6379SourceSecurityGroupId: !Ref EC2SecurityGroup- Description: Allow access from Code ServerIpProtocol: tcpFromPort: 6379ToPort: 6379SourceSecurityGroupId: !Ref ApplicationSecurityGroupSecurityGroupEgress:- Description: Allow all outbound trafficIpProtocol: -1CidrIp: 0.0.0.0/0VpcId: !Ref VPCServerlessRedisCache:Type: AWS::ElastiCache::ServerlessCacheProperties:ServerlessCacheName: !Sub ServerlessRedisCache-${AWS::AccountId}Engine: redisCacheUsageLimits:DataStorage:Maximum: 10Unit: GBECPUPerSecond:Maximum: 5000SubnetIds:- Ref: PrivateSubnetOne- Ref: PrivateSubnetTwoSecurityGroupIds:- Ref: RedisSecurityGroupServerlessRedisCacheEndpoint:Type: AWS::SSM::ParameterProperties:Name: !Sub /litemall/prod/redis/endpointType: StringValue: !GetAtt ServerlessRedisCache.Endpoint.AddressDescription: Redis Cache EndpintOutputs:CodeServerPassword:Description: VSCode-Server PasswordValue: !Ref AWS::AccountIdExport:Name: !Sub ${AWS::StackName}-CodeServerPasswordCodeServerURL:Description: VSCode-Server URLValue: !Sub https://${CloudFrontDistribution.DomainName}/?folder=${HomeFolder}Export:Name: !Sub ${AWS::StackName}-CodeServerURLDatabaseName:Description: Database NameValue: litemallExport:Name: !Sub ${AWS::StackName}-DatabaseNameDBMasterUsername:Description: DB Master UsernameValue: !GetAtt DBMasterUsername.ValueExport:Name: !Sub ${AWS::StackName}-DBMasterUsernameDBMasterPassword:Description: DB Master PasswordValue: !GetAtt DBMasterPassword.ValueExport:Name: !Sub ${AWS::StackName}-DBMasterPasswordDBClusterEndpoint:Description: DB Cluster EndpointValue: !GetAtt DBClusterEndpoint.ValueExport:Name: !Sub ${AWS::StackName}-DBClusterEndpointRedisCacheEndpoint:Description: Redis Cache EndpintValue: !GetAtt ServerlessRedisCacheEndpoint.ValueExport:Name: !Sub ${AWS::StackName}-RedisCacheEndpointPrivateSubnetOneID:Description: Private Subnet One IDValue: !Ref PrivateSubnetOneExport:Name: !Sub ${AWS::StackName}-PrivateSubnetOneIDPrivateSubnetTwoID:Description: Private Subnet Two IDValue: !Ref PrivateSubnetTwoExport:Name: !Sub ${AWS::StackName}-PrivateSubnetTwoIDApplicationSecurityGroupID:Description: Application Security Group IDValue: !Ref ApplicationSecurityGroupExport:Name: !Sub ${AWS::StackName}-ApplicationSecurityGroupID

5)在浏览器中打开堆栈的“输出”页面中"CodeServerURL"字段值.

6)打开链接后,显示出 Code Server 的开发环境的登录界面。登录密码是 “输出” 中"CodeServerPassword"的值。

 7)点击“SUBMIT”登录,就可以看到Code Server的IDE开发界面了

2. 下载示例代码库,并修改配置文件

接下来我们将下载电商应用代码库,配置数据库和本地开发环境。

下载 Github 代码库

1)在Code Server网页IDE中运行以下命令

git clone https://github.com/aws-samples/build-serverless-ecommerce-application-with-genai.git .

初始化 MySQL 数据库

2) 回到Cloudformation堆栈的“输出中”中找到 "DatabaseName", "DBClusterEndpoint", "DBMasterPassword", 和"DBMasterUsername"字段的值。

3)打开 IDE 左侧的 SQLTools 插件,点击 "Add New Connection" 按钮,点击 MySQL 图标。

4) 将取出的值输入connection name, Server Address, Database 和 Username。

5) 点击 "TEST CONNECTION"测试连接是否成功,点击 "ALLOW"

 6)在弹出框中输入刚提取的"DBMasterPassword" 的值, 然后回车。

7)测试成功会显示“successfully connected”,这时点击“save connection”

8)双击 SQLTools 插件中新建好的 connection,连接到数据库。

9)在 Explorer 中打开 "litemall-db/sql/litemal_table.sql", 然后点击 "Run on active connection" 来新建 litemall 的数据库表。

10)在 Explorer 中打开 "litemall-db/sql/litemal_data.sql", 然后点击 "Run on active connection" 来导入 litemall 的演示数据。

配置.env 文件

11) 为了方便本地开发测试,我们使用 .env 文件来配置项目的环境变量。运行下面的命令,并填入之前堆栈中的“输出”字段数据对应的值。

cd /Workshop
cp .env.example .env
填入后如图所示

 Maven 下载依赖、编译、打包

在 VS Code 中打开终端并进入项目根目录下,执行 maven 命令进行项目编译

mvn clean
mvn install
mvn clean package

编译成功后终端内如下图所示 

以上就是亚马逊云科技上消除电商场景下的无服务器应用架构的冷启动时间的上篇内容,在本篇中我们在云端编译了我们的电商场景化应用项目,配置了数据库,下篇中我们将介绍利用web adapter云迁移和无服务器服务冷启动的方案。欢迎大家关注小李哥和本系列的下篇,不要错过未来更多国际前沿的AWS云开发/云架构方案。 


http://www.ppmy.cn/server/159508.html

相关文章

Tabby - 开源的自托管 AI 编码助手

Tabby 是一个开源的自托管 AI 编码助手。使用 Tabby&#xff0c;每个团队都可以轻松设置自己的 LLM 驱动的代码完成服务器。独立式&#xff0c;无需 DBMS 或云服务。OpenAPI 接口&#xff0c;易于与现有基础设施&#xff08;例如 Cloud IDE&#xff09;集成。 支持消费级 GPU。…

vue编写一个可拖动的模块,并可以和任何其他组件组合使用

实现思路&#xff1a; 使用 Vue 的自定义指令&#xff08;directive&#xff09;来处理拖动逻辑。在 mounted 钩子中添加鼠标事件监听器&#xff0c;以实现拖动功能。在 unmounted 钩子中移除鼠标事件监听器&#xff0c;防止内存泄漏。 代码示例&#xff1a; <template&g…

前端小知识 鼠标穿透 pointer-events: none;

为什么会说到这个呢&#xff1f;是我觉得没有识别出来&#xff0c;然后就导致了这样的问题&#xff0c;这种情况不应该发生。我写了如下这样一段代码&#xff0c;但是发现当自己选择时间的时候无法选择。然后就发现变成了光标在闪烁。这样其实就是因为我选择到了这个input框的鼠…

STM32--定时器输出pwm知识点_stm32 pwm-CSDN博客

1. 选择TIM_OCMode_Toggle电平翻转模式&#xff0c; TIM_TimeBaseInitStruct.TIM_Period PWM_1_TIM_Period; 要设置成PWM_1_TIM_Period设置成0xffff - 1&#xff0c;设置成其他数值会出现脉冲一会有一会咩有。 资料&#xff1a;一文搞懂STM32定时器翻转模式&#xff08;产生…

SQL Server 导入Excel数据

1、选中指定要导入到哪个数据库&#xff0c;右键选择 》任务 》导入数据 2、数据源 选择Excel&#xff0c;点击 下一步(Next) 3、目前 选择OLE DB Provider &#xff0c;点击 下一步&#xff08;Next&#xff09; 4、默认 &#xff0c;点击 下一步&#xff08;Next&#xff09;…

JAVA-Exploit编写(3)--httpcomponents库使用文件上传

目录 1.依赖安装 2. upload文件代码 3.文件上传代码 1.依赖安装 文件上传处需要使用httpcomponents库,需要在Maven的pom.xml文件中导入依赖 <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId>&l…

用LLM做测试驱动开发:有趣又高效的尝试

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

基于 Python 的毕设选题管理系统设计与实现

标题:基于 Python 的毕设选题管理系统设计与实现 内容:1.摘要 本文介绍了一个基于 Python 的毕设选题管理系统的设计与实现。该系统旨在解决传统毕设选题管理方式中存在的效率低下、信息不透明等问题。通过使用 Python 语言和相关技术&#xff0c;实现了对毕设选题的信息化管理…