AWS Lambdaを使えば開発者がビジネス価値に集中できる一方、それでも今までの開発と異なるポイントに気をつける必要があります。この記事では注意したい計30個のチェックポイントを紹介します。
まずは比較的簡単で効果が出やすい部分から見ていきましょう。
🚀時間がないあなたに!すぐできるポイント10選
レビューしていてよく出てくる、比較的修正しやすい事項です。
(1) メモリサイズを設定する
LambdaはメモリサイズによってCPU含めたリソースパワーが決まり、1792MBで1CPUちょうどとされています。利用言語やマルチスレッド処理の状況に合わせ増減させましょう。
デフォルトはCloudFormationやCDKなら128MB、Serverlesssで512MBと少なめです。ユーザーが使うAPIなら必ず設定しましょう。
(2) arm64(Graviton2)を前提とする
Lambdaではアーキテクチャが選択できます。コストもパフォーマンスもデフォルトのx86_64よりarm64が優れているので、最初からこちらを利用しましょう。バイナリ等を使っているとうまく動かないことがあるので注意。Lambda Layerもarm64対応のものを選んでくださいね。
(3) Node.js限定: TCP keep aliveを入れる
ベストプラクティスにも記述がある通り、AWS_NODEJS_CONNECTION_REUSE_ENABLED=1
を環境変数に入れましょう。httpリクエストのパフォーマンスが上がります。
なお、@aws-cdk/aws-lambda-nodejs では自動的に設定されます。
(4) Lambda Power Toolsを利用する
複数言語に対応した、構造化ログを含めた便利なライブラリです。ログだけではなく冪等性処理なども簡単に実装できます。まずは利用してみましょう。
Python版 https://awslabs.github.io/aws-lambda-powertools-python/latest
(5) Step Functionsでの代替を検討する
Lambda間の呼び出しや非同期処理、ユーザー行動待ちといったワークフローはStep Functionsが得意とするところです。Synchronous Express Workflowsなら同期処理でもOK。複雑なAPIならぜひ検討を。
(6) 転送のみ行うLambdaなら削除を検討する
サービス間の転送(Transport)だけを行うLambdaは廃止できることがあります。
API Gateway -> S3
のように、サービスによっては直接接続できますし、Step Functionsならほとんどのサービス同士を直接つなげることができます。マッピングのような加工も一部のサービスではLambdaなしで可能です。まずはLambdaなしでも可能かどうか考えてみましょう。
(7) フィルタリングを利用する
SQSやDynamoDB Streams、Kinesis Data Streamsといった非同期系のLambdaについて、イベントの内容に応じてLambda実行するかどうかフィルタリング可能です。Lambda関数内でガード文を記載するよりAWSに任せたほうが、簡単便利かつ早く低コストになります。
SQSでエラーになったメッセージだけフィルタリングして再実行するなら、部分バッチ応答機能を使いましょう。SQSで「バッチ項目の失敗を報告する」を設定し、Lambda関数内のエラー処理を若干書き換えればOKです。
(8) CI時コードのみデプロイを検討する
IaCツールやフレームワークによりますが、デプロイコマンドですべてのCloudFormationを実行する仕組みになっていることがあります。
例えば以下のようなオプションでコードのみデプロイとなり、デプロイが高速化できます。
serverless deploy function -f 関数名
cdk deploy --hotdeploy
CDKのほうは本番利用は避けてほしいとのことです。
(9) モニタリングする
組織で利用しているツールに基づき実装検証しましょう。
(10) ベストプラクティスを読み込む
公式ドキュメントを読み、各項目の内容を例を挙げて説明できるようにしましょう。AWSはドキュメントは厚いのですが探しづらい傾向がありますね。
📚さらに開発運用しやすくするための上級編 14選
前記10選よりもう少し難易度の高い内容です。いますぐ全部できている必要はありませんが、徐々にこなしていきたいところです。
泥団子巨大Lambdaを避ける
影響範囲の分離がLambdaの売りの1つです。1つのLambdaで全てすませるのではなく、コードベースの成長に合わせ適宜Lambdaを分割しましょう。例えばルーティングはLambda内ではなく、API Gatewayといった別のマネージドサービスに任せられます。セキュリテイの面でも権限分割が重要ですし、コールドスタート時の時間も短くなります。ローリングアップデートもしやすくなりますし、ライブラリバージョンアップも1Lambdaづつ行うほうが安全です。
タイムアウト時間を明示的に設定する
Lambdaに限ったことではないですが、デフォルトのまま、暗黙のままは避けましょう。秒数を明確に決めて即答できるように。
Lambdaタイムアウト時の処理を検討、試験する
タイムアウト時は後処理が実行されず、タイムアウトした旨のログが1行出るだけです。タイムアウト時に自分でログを出すといったことはできません。Lambdaを呼び出す側としては通常のエラー処理とは別に、タイムアウト時のハンドリングも考慮が必要です。
なおNode.js版のLambda Power Toolsならタイムアウト直前のログ実行機能が使えます。
利用ライブラリを最小限に抑える
ベストプラクティスにも一部記載がある通り。言語によっては一部だけ指定してrequireしましょう。特にAWS SDKは巨大なので注意が必要です。Node.jsではnode-pruneやmodclean、uglify-esなどによるサイズ削減を検討してみましょう。
API Gateway: 簡単なバリデーションはAPI Gateway側でも検討する
簡単な型チェックならAPI Gateway側で行えばLambdaを呼び出さずにすみます。一方アプリケーションログの整合性、バリデーションロジックの重複は考慮しておきましょう。
Node.js限定 callbackWaitsForEmptyEventLoop = falseを検討する
主にコネクションプールの再利用が早くなります。各種動作が想定通りか検証しておきましょう。
Node.js イベントループが空になるまで待機せずに、コールバックが実行されるとすぐにレスポンスが送信されます。これが false の場合、未完了のイベントは、次の呼び出し中に実行され続けます。
必要ならコールドスタート対策をする
コールドスタート回数を減らしたいなら、定期的に呼び出す、provisioned concurrencyを利用するといった方法があります。
コールドスタート時間を短くしたいなら、ファイルサイズ削減やLambdaの分割をしましょう。
Provisioned ConcurrencyをAuto Scalingさせる
Provisioned ConcurrencyはAPI経由ならAuto Scalingが設定でき、方式は負荷または時間帯ベースです。Provisioned Concurrencyは地味に高いので節約にもなります。
Serverless Frameworkでの事例
同時実行数割当を確認する
アクセス量が多い場合。固定数を割り当てることで、該当Lambdaの同時実行数を確保することと、アカウント全体の他の同時実行数に影響を与えないことが担保される。同時実行数割当は村から出ていって自分の食料を別枠で担保するイメージです。村の食糧事情とは関係なくなりますが、自分の分がなくなったら餓死してしまいます。アカウント全体の同時実行数はコンソールからの申請により増加可能です。
テストはクラウド環境で行うことを検討する
利用分だけの支払いのため、本番に近い環境での試験でも安価です。とはいえ技術スタックや開発者の好みも考慮して検討しましょう。
メモリ設定が少ないLambdaを洗い上げる
メモリ設定が少ないLambdaを横断して洗い上げたいときがあります。Datadogなどのモニタリングツールを使うか、AWS Configを設定していればAdvanced Queryを使いクエリにて検索できます。クロスアカウントでの検索も可能です。
Serverless Framework: プラグインを検討する
- serverless-prune-plugin: Lambdaのバージョンがたまりすぎるのを防いでくれる
- Serverless Optimize Plugin: バンドルの最適化をしてくれる
などなど。一方、プラグインあるあるで古くなってないか、もう不要でないかも時折確認しましょう。
巨大バイナリライブラリはLambda Layerの利用も検討する
ffmpegなど巨大なバイナリはLambda Layerに移すことでコードサイズが減り、コールドスタート時の速度向上を狙えます。ただしLambda Layerを利用するとテストや開発しづらい面はあります。
Intel限定 AVX2でコンパイルしたものをアップロードする
そもarm64(graviton2)を前提としつつ、AVX2ならffmpeg2, numpy、機械学習系ライブラリなどのベクトル計算系はパフォーマンス向上が見込めます。通常のpip経由ではavx2/MKL対応にならないので注意
🏞️ストリーム系のちょっとしたポイント編 6選
ストリーム系はまた異なる点があります。
バッチサイズとウィンドウを設定する
KinesisのようなEvent Source Mapping系では設定しましょう。IaCツールによってbatchsizeとウィンドウのデフォルトが異なるので、念のため確認しておきましょう。
bisectBatchOnFunctionError を検討する
バッチ失敗時に2分割して再度実行してくれます。冪等性周りは確認しておきましょう。
カスタムチェックポイントを検討する
エラー時の計算量によっては検討しましょう。とにかくエラーが発生したときどうするか、運用にあたり肝心な点です。
Kinesis: startingPositionの活用
Kinesisのトリガーを新しく設定すると、デフォルトでは1年分の過去ログを全部読み直す動作です。必要に応じてstartingPosition = LATEST
にしておきましょう
Kinesis: parallelizationFactorの検討
シャードあたりのlambda実行数を増やすことができます。
ストリームもモニタリングする
漏れがちです。すべてモニタリングしましょう。
📄まとめ
Lambdaはなんとなくでも動いてしまうのも良いところではありますが、本番環境ではそれでは物足りないことも多いでしょう。最初の10選だけでも今すぐ見直してみましょう。そうすれば顧客に価値を届けやすくなります。
文責: 高木