「AWS Black Belt Online Seminar Let’s dive deep into AWS Lambda Part3 」の自分向けメモ
Lambda使ったことない......レベルの人向け
コールドスタート概要
- 関数コードのダウンロード
- コンテナの開始
- runtimeの起動 ←ここまでコールドスタート
- 関数コードの実行
1.2.はAWSが最適化するところ
3.4.はユーザーが最適化するところ
X-Rayをつかうことでコールドスタートを確認できる
- Initializationがコールドスタート部分
- LambdaからVPCアクセスにした場合、ENI作成等にかかる時間が別途必要になる
- Warm Startの場合は、ENI作成とコールドスタート部分がない
コールドスタートを速くする
関数コード実行のベース部分を速くする
コンピューティングリソースを増やす
- Lambdaのメモリ設定はパフォーマンス設定と同様
- コストが上がるが処理時間が減ることで、コスト的には変わらない場合もある
- 少しずつ、リソースを増やしていき、性能が変わらなくなる値が最適値
ランタイムを変更する
- JVMは比較的遅い
パッケージサイズを小さくする
関数コードのダウンロード時間の短縮につながる
コードを減らす
- Javaの場合、依存するjarファイルを個別の/Libディレクトリに格納する
依存関係を減らす
- 不要なモジュールは含めない
- Javaは肥大しがち
VPCはなるべく使わない
- VPC内のリソースにアクセスする必要があるときだけ使う
- RDSなどパブリックに公開できないリソースは仕方ない
- アクセスポリシーで保護して、エンドポイントをパブリックに公開する
コードを速くする
効率的な関数コード
- コードの最適化
- 1つの関数はなるべく単機能にする
- 呼び出し(handler)とビジネスロジックの分離
- 単体テストが容易
コンテナ再利用を有効活用する
- DBの接続処理をハンドラの外側で行うことで、毎回処理されるhandler以下の処理を減らせる
必要な情報のみ読み込む
- S3の情報をとる場合、絞り込んで取得する
コード内でオーケストレーションしない
- 子ファンクションを呼び出すとステート管理やエラーハンドリングが複雑になりやすい
- 子ファンクションの処理の間に親ファンクションがタイムアウトになりやすい
- Step Functionを利用する
レジリエンシの向上
- エラーハンドリング
- 外部接続時の適切なタイムアウト
- AWSサービスのタイムアウトは1秒でいい
- 明示的に設定しないとログが残らない可能性がある
- リトライ処理を実装する(Exponential Backoff with Jitter)
- Lambdaのリトライポリシーを理解すること
- Dead Letter Queueを活用すること
複雑な依存関係を避ける
- 単純なフレームワークを利用する
- 実行時のロード時間を短くする
組み込みSDKは使用しない
- Lambdaの実行環境では組み込み済みで、関数コードから利用可能
- 組み込む場合は、自前で管理が必要
非同期実行を活用する
- 同期でInvokeすると同時実行数の制限にひっかかり、エラーとなる
- スケーラビリティの観点では非同期がおすすめ
- 非同期実行をする場合、Dead Letter Queueの設定をすること
冪等性を確保する
- 冪等性は自前で確保する必要がある
- イベントIDをDynamoDBに保管して、処理実行前に存在しなければ実行
- 処理全でバケットを分け、処理後に消す
- 処理前のバケットが残っていたら、未実行だと気づける
Think Parallel
- 並列処理で同時実行することが重要
- 1つあたりのイベントを小さくして同時に並列で動かせるアーキテクチャにする
- ループ処理はループ回数分Lambdaを非同期Invokeする
ハードコーディングしない
- パフォーマンスには影響しないが
- コードと設定を分離(環境変数を利用)することでステージごとの切り替えも容易になる
- 認証情報のハードコーディングはリスクもはらむ
- SSMのParameter Store:設定データ管理と機密管理のためのストレージ
- 環境変数や気密情報の一元管理が可能
- レイテンシが高くなるのでなるべくキャッシュする
- SSMのParameter Store:設定データ管理と機密管理のためのストレージ
ストリーム型イベントソース利用時
- Kinesis Data StreamsやDynamoDBストリームのシャード数とLambda関数の同時実行数は同じ
- Lambda関数のバッチサイズが大きいと同時実行数は低下する
- バッチサイズ:Lambda関数の実行当たりの最大レコード数
- 処理が失敗するとブロックされ、リトライされない。
- 1シャードに複数Lambdaからのアクセスはスループットの低下を招く
- ファンアウトパターン:一つのファンクションで読み込み、処理は配下のファンクションで行う
- 順序が重要ではない場合は、SNSを利用すること
データベースの利用について
LambdaとRDSはアンチパターン
- コネクション数の問題
- Lambdaはステートレスであるため、コネクションプールの実装が難しい
- Lambdaがスケールアウトすると、RDSのコネクションが枯渇する
- VPCコールドスタートの問題
- 通常のコールドスタートより10秒程度の時間を必要とする
- 以下は影響がでにくいので問題ない
- 実行数が少ない
- VPCコールドスタートの遅延が許容できる
DynamoDBを利用する
- スループットがスケーラブル
- VPC外サービス
RDSへの反映を非同期にする
- DynamoDBストリームとLambdaを利用
- Kinesis Data StreamsやSQSとLambdaを利用
同時実行数の制限
- Lambdaのスケールアウトを制限する
- ファンクション単位に設定可能
- 全ファンクションでやるのではなく、RDSを利用するファンクションをまとめる
- VPCコールドスタートの問題は残る
Aurora Serverless Data API
- コネクション管理不要でAuroraを利用できるHTTPSエンドポイント
- トランザクションなし
IP固定したい
- アンチパターン
- 署名や証明書で担保するべき
すべてをサーバーレスで実現することはできない
- ステートフルなアプリ
- ロングバッチ
- スペック
サーバーレスアプリのライフサイクル
- 以下サービスで開発~デプロイまで対応可能
- AWS Lambda console
- IDE plugins
- AWS Cloud9
- テキストエディター + AWS SAM
- サーバーレスアプリに最適化したCloud Formationテンプレート
テスト
- ユニットテストはローカルで
- インテグレーションや受け入れテストは実際に使う
- mockは複雑
- SAM CLIを利用したローカル開発
CI/CDのパイプライン
CodePipelineを使って、リリースする
- GitHubまたはCode CommitからソースをPull
- Code Buildでビルドとパッケージング
- Code DeployおよびCloud Formationでデプロイ
- サードパーティツールによるテスト
- Cloud FormationやAWS SAMで本番デプロイ
移行時
- エイリアスを利用したトラフィックテスト
- 徐々に切り替えが可能
Part3はここまで。