【AWS Lambda】エラーハンドリングの基礎 - Design for Failure -

2022/06/20に公開

Lambdaのエラーハンドリングについて、
『AWS Japan Summit Online 2020』のオンラインセッションで学んだ [ Design for Failure ] の考え方をまとめます。

Lambdaの実行中には様々なエラーが予想されるため、それらに適切に対応するためのデザインが必要です。

Lambda で エラー になると

Lambda関数はエラーを受け取ると基本的に複数回リトライを行います。不要なリトライは、膨大なログデータを発生させたり、無限にリトライし続けることで膨大な料金になってしまうことも考えられます。

そのため、エラーに適切な対処ができるようあらかじめ準備する必要があります。

エラーへの対処

エラーへの対処には、主に以下3つの方法が考えられます。

  1. 不要なリトライの回避
  2. エラー伝播の回避
  3. データ整合性の確保

1. 不要なリトライの回避

無駄なリトライはトラブルの元です。リトライ設計を適切に考える必要があります。

リトライ設計で考慮するポイントは以下の通りです。

  • 誰がリトライを実施するのか
  • どれくらいの期間・何回リトライするのか
  • イベントデータの行き先(退避先)はあるか
  • 退避されたイベントデータのモニタリング・処理

イベントソースごとに異なるリトライ制御を考える

イベントソース(つまりLambdaにイベントを渡す元)によって、制御で考慮するポイントが異なります。

  • イベントソースごとに適切なリトライ回数を設定する
  • イベントソースごとに適切な失敗時のイベント送信先を設定する

2. エラー伝播の回避

エラーが不要に伝播することも、避けなければなりません。
主に、以下2点に注意して設計を行います。

  • エラーを受け取らない
  • エラーしか受け取らなくなった場合にそれ以上受け取らないようにする

エラーを受けとならい

以下2点について設定を行うことで、処理結果による分岐が可能です。

  • 非同期呼び出しによるLambda関数の起動
  • SQSやSNSなどのコンポーネントを関数チェーンの間に差し込む

緊急停止を実装しておく

エラーしか受け取らなくなった場合にそれ以上受け取らないようにするよう、あらかじめ設定を行います。

  • CloudWatchメトリクスのErrorsをモニタリングする
    • 閾値を超えた場合に緊急停止します。
  • 緊急停止後の回復を策定する
    • AWS Step Functionsなどで緊急停止後のワークフローを設定する

3. データ整合性の確保

エラー時のデータ不整合への対策を行います。データの不整合には以下の2つのケースが考えられます。

  • 処理済みのリクエストを再度処理したケース
  • 1つのプロセス内で複数のリソースを更新するケース

処理済みのリクエストを再度処理したケース

バッチ(複数のレコード処理)を起動中にエラーが発生すると、すでに完了済みのレコードについても再度リトライが発生するなどのケースです。以下2点について忘れずに設定を行うことで対策が可能です。

  • 重複処理を排除する
    • 処理ずみの判定チェックをDBで管理するなど
  • 重複処理を許容する
    • 重複によりエラーやデータ不整合対策をロジックで解消する

1つのプロセス内で複数のリソースを更新するケース

一つのLambdaで複数のリソースを更新する場合があります。一つのLambdaでDynamoDBとAuroraの両方を更新するケースなどです。

例えば以下のような場合、確定したDynamoDBのデータ変更を取り消してリトライする仕組みが必要です。

  • DynamoDBの更新は成功したが、
  • Auroraの更新が失敗した

反対処理による取り消し(Compensation Transaction)

データ変更の取り消しとは、成功した処理の逆の処理を行うことです。(反対処理)
具体的には、AWS Step Functionsを活用し、個別の関数を組み合わせたワークフローとして実装することができます。

  • 反対処理の実装を全てのロジックに行うと、膨大な記述が必要です。
    • そのため、ステートマシン(AWS Step Functions)を利用した制御が推奨されています。

まとめ

エラーへの対処として以下3つのポイントがありました。

  1. 不要なリトライの回避
  2. エラー伝播の回避
  3. データ整合性の確保

また、これらを実現するために、疎結合な小さなコンポーネントの組み合わせで処理を実装することが大切です。


参考

https://docs.aws.amazon.com/whitepapers/latest/running-containerized-microservices/design-for-failure.html

Discussion