Developers.IO 2019 in 福岡で「劇的改善??VPC Lambda Before&After」というテーマで発表させていただきました #cmdevio

2019/10/26に開催されたDevelopers.IO 2019 in 福岡で「劇的改善??VPC Lambda Before&After」というテーマで発表させていただきました。その際の発表資料です
2019.10.28

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

CX事業本部の岩田です。

2019/10/26に開催されたDevelopers.IO 2019 in 福岡で「劇的改善??VPC Lambda Before&After」というテーマで発表させていただきました。お越し下さった皆様ありがとうございました。モツ鍋うまかったです。

発表資料はこちらです。

このブログでは発表内容について簡単に説明させて頂きます。

AWS Lambdaのアーキテクチャおさらい

Lambdaのアーキテクチャはこのようなレイヤ構成になっています。

Lambdaのアーキテクチャ

Lambda Workerと呼ばれるEC2インスタンスの上でMicroVMと呼ばれる仮想マシンが起動し、さらにMicroVMがLinuxカーネルの

  • cgroups
  • namespaces
  • seccomp
  • iptables
  • chroot

といった機能を使って、プロセス毎に隔離されたサンドボックス環境を構築します。構築されたサンドボックス環境内にNode.js、Pythonといった言語のランタイムが乗っかり、さらにその上で我々ユーザーの作成した関数のコードが実行されます。

Lambdaの実行要求があった場合に、構築済みのサンドボックス環境が存在しない場合は、新たにサンドボックス環境の構築や初期化を伴います。これがいわゆるコールドスタートです。また、大量アクセスによって多数のサンドボックス環境を起動するようなケースでは、WorkerManagerやPlacement Serviceといったコンポーネントと連携して、Worker自体の割り当てから実行されます。さらに、このモデルはEC2モデルとFirecrackerの2種類に分かれます。

EC2モデル

まずはEC2モデルです。こちらのモデルはLambdaというサービスが登場した当初から利用されているモデルです。NitroプラットフォームのEC2上で動作するMicroVMにLambdaの実行環境が構築されます。

Lambdaのアーキテクチャ(EC2)

こちらのモデルでは1つのMiroVM上に複数のLamba実行環境が構築されます。また、WorkerはAWSアカウントと1:1に紐付きます。AWSアカウントをまたいでWokkerが共有されることはなく、Worker単位で環境分離が実現されます。

Firecrackerモデル

続いてFirecrackerモデルです。まずFirecrackerとは何か?ですがKVMをベースにAWSがクラウド時代に向けて開発した新しい仮想化技術です。これまでの仮想化技術に比べて、高速かつメモリの消費量を抑えて仮想マシンを起動することが可能です。このFirecrackerはFargateの基盤で利用されているのに加えて、Lambdaの基盤でも利用されています。

Lambdaのアーキテクチャ(Firecracker)

Firecrackerモデルでは、MicroVMを起動するオーバーヘッドが非常に小さいため、1つのEC2ベアメタルインスタンス上で何10万ものMicroVMが起動しているそうです。FirecrackerモデルではAWSアカウント間の境界はMicroVMになり、複数のAWSアカウントが1つのWorkerを共有利用することになります。

VPC Lambdaのアーキテクチャ(旧)

ここからはVPC Lambdaのアーキテクチャについての話です。元々のVPCLamdbaのアーキテクチャはこの図のようになっていました。

VPC Lambdaの旧アーキテクチャ

※画像はAnnouncing improved VPC networking for AWS Lambda functionsより引用

まずLambdaの実行環境はAWSが管理する専用のVPC内に構築されます。そして、Lambdaが顧客のVPC内のリソースにアクセスする際には顧客のVPC内にENIを作成し、作成したENIを経由してVPC内のリソースにアクセスするようなモデルです。このENIはLambda実行環境のメモリ使用量3G毎に1つ作成されていました。

Lambdaのメモリ割り当て上限は3Gですが、メモリを3G割り当てたLambdaが1つ起動した場合はENIを1つ、メモリを3G割り当てたLambdaが2つ同時に起動した場合はENIを2つ消費するようなモデルです。

少し表現を変えるとこのようなイメージになります。

VPC Lambdaの旧アーキテククチャ2

※画像はA Serverless Journey: AWS Lambda Under the Hood (SRV409-R1) - AWS re:Invent 2018より引用

こちらはre:invent2018のセッションで紹介されていたVPC Lambdaのモデルです。Lambda実行環境から顧客VPC内のENIのNAT処理はWoker内で実行されるという説明です。旧アーキテクチャのVPC Lambdaでは1つのENIに対して1つのWorkerがアタッチされ、Workerを跨いでENIを共有することができませんでした。

まとめると旧アーキテクチャでは

  • Worlkerを跨いでENIを共有できない
  • メモリ3GB毎にENIを消費する

という特徴がありました。

VPC Lambdaが抱えていた課題

このようなモデルの旧アーキテクチャは様々な問題を抱えていました。

  • ENIの枯渇問題
  • ENI作成のRate Limit
  • IPアドレス枯渇問題
  • ENI作成を伴うコールドスタート時の遅延
  • インターネットアクセスにNAT Gatewayが必要

などです。

また、VPC Lambdaを使う動機としてはRDB(S)を利用したいという動機が一番多いと思います。このRDB(S)とLambdaの組み合わせにも課題があります。

  • 同時接続数の問題
  • コネクションプーリングが使えない
  • RDBはスケールアウトではなくスケールアップ
  • コスト最適化の課題

といった課題です。 この辺りは以前の発表で詳しく取り上げているので良ければご参照下さい。

これらの課題から、VPC Lambdaはアンチパターンとされていました。

VPC Lambdaのアーキテクチャ(新)

ここからVPC Lambdaの新アーキテクチャについてです。

旧アーキテクチャではLambdaのコールドスタート時に必要に応じてENIを作成してWorkerにアタッチしていましたが、新アーキテクチャではVPC Lambda作成時にサブネットとセキュリティグループの組み合わせごとにENIを1つ作成します。Lambdaのサンドボックス環境はWorkerを跨いでこの1つのENIを共有利用します。

VPC Lambdaの新アーキテクチャ

※画像はAnnouncing improved VPC networking for AWS Lambda functionsより引用

Lambda実行環境と顧客VPC内のENIのNAT処理に関しては、Lambda実行環境とENIの間のHyperplaneENIというコンポーネントが実行するようになります。

Hyperplaneについて

このHyperplaneとはAWSのサービス内部で利用されているSDNの技術です。元々はS3LoadBalancerで利用されていた技術をベースに開発されたコンポーネントです。

  • EFS
  • NLB
  • Private Link
  • Managed NAT(NAT Gateway,Transit Gateway)

で利用されており

  • デフォルト5Gbit/secの性能をもつ
  • Tbit/secレベルまでスケールする
  • msレベルのレイテンシー

といった特徴を持ちます。

Hyperplaneに関する説明

※画像はAmazon VPC: Security at the Speed Of Light (NET313) - AWS re:Invent 2018より引用

VPC LambdaでもこのHyperplaneの技術を利用して顧客のVPC内のENIにNAT処理を行うことで、最小限のオーバーヘッドでVPC内のリソースと通信することが可能になりました。

東京リージョンに新アーキテクチャの適用が完了しました!!

Update – September 27, 2019: We have fully rolled out the changes to the following Regions: US East (Ohio), EU (Frankfurt), and Asia Pacific (Tokyo). All AWS accounts in these Regions will see the improvements outlined in the original post.

Announcing improved VPC networking for AWS Lambda functions

という訳で9/27に東京リージョンへの新アーキテクチャ適用が完了したというアナウンスがありました。

改善効果について

新アーキテクチャで色々検証してみました。ここからは私の方で実施したいくつかの検証結果のご紹介です。

検証1 EC2インスタンスからheyコマンドを50並列で流した場合

5/29に実施した時点では、500回中50回のリクエストに関しては10秒以上の大きな遅延が発生していました。

Summary:
  Total:  13.4614 secs
  Slowest:  13.0460 secs
  Fastest:  0.0194 secs
  Average:  1.2528 secs
  Requests/sec: 37.1433
  
  Total data: 2500 bytes
  Size/request: 5 bytes
  
Response time histogram:
  0.019 [1] |
  1.322 [448] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  2.625 [1] |
  3.927 [0] |
  5.230 [0] |
  6.533 [0] |
  7.835 [0] |
  9.138 [0] |
  10.441 [4]  |
  11.743 [9]  |■
  13.046 [37] |■■■

また、9/16に実施した時点でも、10秒以上の大きな遅延が発生したり、しなかったりという状況でした。※9/16時点ではAWSからVPC Lambdaの改善提供完了の正式アナウンスはありませんでした。順次更新中という段階だったと思われます。

10/20に改めて同一の検証を流したところ、1秒以上の遅延は一度も発生しませんでした。

Summary:
  Total:	1.3694 secs
  Slowest:	0.5470 secs
  Fastest:	0.0225 secs
  Average:	0.0970 secs
  Requests/sec:	365.1342

  Total data:	2500 bytes
  Size/request:	5 bytes

Response time histogram:
  0.023 [1]	|
  0.075 [411]	|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.127 [25]	|■■
  0.180 [1]	|
  0.232 [0]	|
  0.285 [0]	|
  0.337 [0]	|
  0.390 [9]	|■
  0.442 [7]	|■
  0.495 [33]	|■■■
  0.547 [13]	|■

検証2 EC2インスタンスからheyコマンドを500並列で流した場合

新アーキテクチャではWorkerを跨いでENIを共有できるようになり、メモリ使用量合計3Gの制限はなくなりました。ただ、常に消費するENIが1つだけかというと、明確なドキュメントの記載は見つけられませんでした。Lambdaの同時実行数がどんどん増えていった場合に、果たしてENIが追加作成されることはないのでしょうか?

※2019/11/30追記 Lambdaのドキュメントに以下のような記載が追加されていました。

関数の数が多い場合や、非常に使用率が高い関数がある場合は、Lambda で追加のネットワークインターフェイスが作成されることがあります。

VPC 内のリソースにアクセスするように Lambda 関数を設定する ※2019/11/30追記 ここまで

Lambdaの同時実行数を高い水準に保つため、

  • Lambdaに2秒のスリープを追加
  • heyの並列数を500に引き上げ

と、条件を変更して改めて検証しました。

Summary:
  Total:	21.8108 secs
  Slowest:	3.4042 secs
  Fastest:	2.0223 secs
  Average:	2.1532 secs
  Requests/sec:	458.4892

  Total data:	50000 bytes
  Size/request:	5 bytes

Response time histogram:
  2.022 [1]	|
  2.160 [8998]	|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  2.299 [1]	|
  2.437 [0]	|
  2.575 [0]	|
  2.713 [0]	|
  2.851 [0]	|
  2.990 [0]	|
  3.128 [113]	|■
  3.266 [844]	|■■■■
  3.404 [43]	|

この検証パターンでも大きな遅延は発生せず、ENIが追加作成されることはありませんでした。

※スリープを2秒追加しているので、純粋な処理時間という意味では2秒引いて考えて下さい。

検証3 Locustのクラスタを作ってLambdaの同時実行数上限を超える負荷をかけた場合

さらに負荷を上げて、Lambdaの同時実行数上限を上回るレベルのアクセスを行います。クライアントとして利用しているEC2のスペックがボトルネックになることを避けるため、Fargateを使ってコンテナ20台で構成されるLocustのクラスタを構築してテストを行いました。

Locustを使ったテスト負荷テストの構成

Locustを使った負荷テストはこちらの記事も参照して下さい。

MQTTの負荷テストもバッチリ!!Locustを活用した分散負荷テスト環境の構築

このブログを書いたときはCFnでサービスディスカバリの設定が出来なかったのですが、今はCFnが対応しているので設定が楽になりました。使用したテンプレートはこちらです。

AWSTemplateFormatVersion: 2010-09-09
Description: Setup Stress Test Environment
Parameters:
  UserGIP:
    Description: The IP address range that can be used to Locust WebUI
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  TargetBaseUrl:
    Description: Target host name for test
    Type: String
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'
      InstanceTenancy: default
      Tags:
        -
          Key: Name
          Value: locust VPC
  PrivateNamespace:
      Type: AWS::ServiceDiscovery::PrivateDnsNamespace
      Properties:
          Name: locust.internal
          Vpc: !Ref VPC
  DiscoveryService:
    Type: AWS::ServiceDiscovery::Service
    Properties: 
      Description: Discovery Service for Locust
      Name: master
      DnsConfig:
        RoutingPolicy: MULTIVALUE
        DnsRecords:
          - TTL: 60
            Type: A
      HealthCheckCustomConfig: 
        FailureThreshold: 5
      NamespaceId: !Ref PrivateNamespace
  VPCPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        -
          Key: Name
          Value: VPCPublicRouteTable
  VPCPublicSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/24
      AvailabilityZone: ap-northeast-1a
      MapPublicIpOnLaunch: true
      Tags:
        -
          Key: Name
          Value: VPCPublicSubnetA
  VPCPublicSubnetARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref VPCPublicSubnetA
      RouteTableId: !Ref VPCPublicRouteTable
  VPCInternetGateway:
    Type: AWS::EC2::InternetGateway
  VPCAttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref VPCInternetGateway
  VPCRoute:
    Type: AWS::EC2::Route
    DependsOn: VPCInternetGateway
    Properties:
      RouteTableId: !Ref VPCPublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref VPCInternetGateway
  VPCLocustSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow Access To Locust
      VpcId: !Ref VPC
  VPCLocustSecurityGroupIngressWebUIInner:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref VPCLocustSecurityGroup
      IpProtocol: tcp
      FromPort: 8089
      ToPort: 8089
      SourceSecurityGroupId: !Ref VPCLocustSecurityGroup
  VPCLocustSecurityGroupIngressMasterSlaveInner:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref VPCLocustSecurityGroup
      IpProtocol: tcp
      FromPort: 5557
      ToPort: 5558
      SourceSecurityGroupId: !Ref VPCLocustSecurityGroup
  VPCLocustSecurityGroupIngressWebUI:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref VPCLocustSecurityGroup
      IpProtocol: tcp
      FromPort: 8089
      ToPort: 8089
      CidrIp: !Sub ${UserGIP}
  VPCLocustSecurityGroupIngressMasterSlave:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref VPCLocustSecurityGroup
      IpProtocol: tcp
      FromPort: 5557
      ToPort: 5557
      CidrIp: !Sub ${UserGIP}
  VPCLocustSecurityGroupIngressSSH:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref VPCLocustSecurityGroup
      IpProtocol: tcp
      FromPort: 22
      ToPort: 22
      CidrIp: !Sub ${UserGIP}
  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - ecs-tasks.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
        - arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
  ECRRepository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: lambdatest/locust
  LocustCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: LocustCluster
  LocustMasterTaskDef:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Cpu: 512
      Family: locust-master
      Memory: 1GB
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
      ContainerDefinitions:
        -
          Command:
            - "locust"
            - "--master"
            - "-f"
            - "test.py"
            - "--host"
            - !Sub ${TargetBaseUrl}
          Image: !Sub
              - '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${RepoName}'
              - {RepoName: !Ref ECRRepository}
          Name: locust-master
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-region: !Sub '${AWS::Region}'
              awslogs-group: !Ref MasterLog
              awslogs-stream-prefix: !Ref MasterLog
  LocustSlaveTaskDef:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Cpu: 2048
      Family: locust-slave
      Memory: 4GB
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn
      ContainerDefinitions:
        -
          Command:
            - "locust"
            - "--slave"
            - "-f"
            - "test.py"
            - "--master-host"
            - "master.locust.internal"
          Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepository}'
          Name: locust-slave
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-region: !Sub '${AWS::Region}'
              awslogs-group: !Ref SlaveLog
              awslogs-stream-prefix: !Ref SlaveLog
  LocustMasterService:
    Type: AWS::ECS::Service
    Properties:
      Cluster: !GetAtt LocustCluster.Arn
      DesiredCount: 0
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
             - !Ref VPCLocustSecurityGroup
          Subnets:
             - !Ref VPCPublicSubnetA
      ServiceName: locust-master
      TaskDefinition: !Ref LocustMasterTaskDef
      ServiceRegistries:
        - RegistryArn: !GetAtt DiscoveryService.Arn
  LocustSlaveService:
    Type: AWS::ECS::Service
    Properties:
      Cluster: !GetAtt LocustCluster.Arn
      DesiredCount: 0
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
             - !Ref VPCLocustSecurityGroup
          Subnets:
             - !Ref VPCPublicSubnetA
      ServiceName: locust-slave
      TaskDefinition: !Ref LocustSlaveTaskDef
  MasterLog:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /ecs/locust-master
  SlaveLog:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /ecs/locust-slave
Outputs:
  LocustCluster:
    Description: LocustCluster
    Value: !GetAtt LocustCluster.Arn
  VPCSecurityGroup:
    Description: VPCSecurityGroup
    Value: !Ref VPCLocustSecurityGroup
  VPCPublicSubnet:
      Description: VPCPublicSubnet
      Value: !Ref VPCPublicSubnetA
  LocustMasterTaskDef:
      Description: LocustMasterTaskDef
      Value: !Ref LocustMasterTaskDef
  LocustSlaveTaskDef:
      Description: LocustSlaveTaskDef
      Value: !Ref LocustSlaveTaskDef

テスト用のコードです

test.py

from locust import HttpLocust, TaskSet, Locust, task, runners
from locust.events import request_success, request_failure
import os
import requests


API_PATH = os.getenv('API_PATH', '/Prod/test')

class APITaskSet(TaskSet):


  @task
  def call_api(self):
    self.client.get(API_PATH)
    # エラーをどう扱うかによって↑のコードと以下のコードを使い分ける
    # with self.client.get(API_PATH, catch_response=True) as res:
    #   if res.status_code == 200:
    #     res.success()
    #   else:
    #     res.failure()


class ColdStartTest(HttpLocust):
  task_set = APITaskSet
  min_wait = 1
  max_wait = 1

Dockerfileです

Dockerfile

FROM python:3.6
WORKDIR /app
ADD Pipfile /app/
ADD Pipfile.lock /app/
RUN pip install pipenv && LIBRARY_PATH=/lib:/usr/lib pipenv install --system --ignore-pipfile
ADD . /app/
  • Lambdaは3秒Sleep後にレスポンスを返却する処理
  • Usersは1,100に設定
  • Hatch rateは100に設定
  • 同時実行数の上限に達するようなワークロード

という設定で、Lambdaの同時実行数上限に到達してスロットリングが頻発されるまで追い込みましたが大きな遅延はありませんでした。

検証4 検証3のレスポンスを1Mに

これまでの検証はLambdaからのレスポンスとしてHelloWorldを返すだけの単純な処理でした。データ転送量が増えた場合にHyperplaneやENIが詰まることが無いか検証するために、Lambdaのレスポンスを1Mに変えて検証しました。

ボツになったテスト

が、、、よく考えたらLambdaから返すレスポンスのサイズを増やしてもHyperplaneやENIの負荷は変わりません。本来はVPC内に何かしら大きめのレスポンスを返してくれるモックサービスを立てて検証するべきでした。この検証は無意味だったので、Speakerdeckにアップした資料からは削除させて頂きましたm(_ _)m

データ転送量の観点など、十分な検証は行えていませんが、それでも今回の検証範囲では新アーキテクチャのVPC Lambdaは非VPC Lambdaと同等レベルの耐久性・可用性がありそうだという結果に終わりました。

どのように考え方を変えるべきか

新アーキテクチャへの移行によって、ENI関連の様々な問題が改善されました。一方でENIと無関係な課題については引き続き課題事項として残り続けます。特にVPC Lambdaを使いたい動機としてニーズの高いRDBに関する同時接続数の課題などは残ったままです。

ただし、本当に同時接続数が問題になるのかは注意が必要です。例えばPostgres互換のAuroraであれば、選択可能な最小サイズのインスタンスであってもデフォルトの最大同時接続数は1600で、Lambdaの同時実行数制限を上回っています。つまり同時実行数の上限緩和申請が必要ないようなワークロードではDBの最大同時接続数に達することは無いわけです。

※Lambdaから複数のDB接続を確立しない実装になっている という前提です

まとめると

  • コールドスタートによる10秒~20秒数100ミリ秒~数秒程度の遅延が許容できるワークロード
  • 利用予定のVPCリソースが想定される最大アクセス数を問題なく処理可能なワークロード

ではVPC Lambdaを採用しても問題ないケースが増えたと言えるでしょう。 例えば、アクセス数が安定しており、数秒程度のレイテンシが許容できるB2Bサービスのバックエンドなどです。

その他 考慮しておきたいこと

最後にその他の考慮事項をいくつか挙げさせて頂きました。

  • VPC Lambdaを使うということは何かしらのVPCリソースにアクセスしたいわけで、そのためのライブラリが必要になることが多いです。自然とLambdaのパッケージやLayerが肥大化しがちで、それに伴ってコールドスタートが遅くなりがちです。
  • 上記の話とも関連するのですが、RDBをバックエンドにしてWeb APIを開発する場合など、何かしらのアプリケーションフレームワークを採用するのか?も要検討だと思います。重量級のフレームワークを採用すると当然コールドスタートは遅くなります。かといってある程度の規模のシステムになるとフレームワークを使わないことによる辛身も出てきます。パフォーマンスや開発の生産性、保守性といった要素から総合的に判断してフレームワークの利用有無を判断しましょう。
  • VPC Lambaが改善されたということで、既存のアプリケーションをLambaに載せ換えることを検討されるケースもあるかもしれません。ちょっとした便利ツール程度であれば良いのですが、中規模〜大規模なモノリシックなアプリケーションをVPCLamdbaに乗せ替えようとしていないでしょうか??マイクロサービス志向で関数単位でデプロイを行うLambdaのモデルとミスマッチにならないかは良く検討した方が良いでしょう。

まとめ

元々VPC Lambdaが抱えていた課題のうち、いくつかの課題は解消されました。しかし、継続して残り続ける課題もあります。とはいえVPC Lambdaを採用しても問題の無いユースケースは増えました。

このようにAWSを利用していると、サービスのアップデートに伴って、それまでの常識が通用しなくなることが頻繁に起こり得ます。常に最新の情報をウォッチしながら自分の知識をアップデートし続けましょう!

参考資料