failure-lambdaを使ってAWS Lambdaへ障害注入する

2020.02.19

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

failure-lambdaはAWS Lambdaに障害を注入するためのNodeモジュールです。 2019-12-23に初回リリースが行われている新しめのツールですね。

SSM Parameter Storeを使うことにより障害注入の設定を行うことが可能です。

注入できる障害の種類は

  • latency
  • exception
  • blacklist
  • diskspace
  • statuscode

です。

今回はこれを使って障害を注入し、どのような結果になるか確認していきたいと思います。

やってみた

リポジトリ にあるexampleフォルダの中にServerless Framework templateがあるので、それを使っていきます

前提

node: v12.13.0

sls: Framework Core: 1.64.0, Plugin: 3.4.0, SDK: 2.3.0, Components Core: 1.1.2, Components CLI: 1.4.0

準備

1. Serverless Framework templateを準備します

$ git clone https://github.com/gunnargrosch/failure-lambda.git

2. exampleフォルダのtemplateでデプロイします

$ npm i failure-lambda
$ cp -r node_modules/failure-lambda/example/
$ cd failure-lambda/example
$ sls deploy

コマンドを実行し、成功すると以下のような出力がされます

Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service failureLambdaExample.zip file to S3 (774 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..........................................
Serverless: Stack update finished...

リソースとしては、

  • SSM Parameter
  • S3 Bucket
  • DynamoDB table
  • Lambda function
  • IAM Role

が作成されます。

failure injection moduleを使用するにはSSM Parameter Storeの値を編集します。 パラメータのキーと値ですが、

  • isEnabled: true, false
    • trueで障害を挿入、falseで無効
  • failureMode: どの障害を挿入するかの選択
    • latency, exception, blacklist, diskspace, statuscode
  • rate: 失敗率の制御。 1, 0.5 など
    • 1は、すべての呼び出しで障害が注入, 0.5はすべての呼び出しの約半分で障害が注入
  • minLatency: ミリ秒単位での待ち時間(最小)
    • failureModeがlatencyの時に有効
  • maxLatency: ミリ秒単位での待ち時間(最大)
    • failureModeがlatencyの時に有効
  • exceptionMsg: 例外とともにスローされるメッセージ
    • failureModeがexceptionの時に有効
  • statusCode: 関数によって返されるステータスコード。
    • failureModeがstatuscodeの時に有効
  • diskSpace: tmpに作成されるファイルのサイズ(MB)
    • failureModeがdiskspaceの時に有効
  • blacklist: 正規表現の配列。
    • 正規表現のいずれかに一致するホストに接続が確立されるとブロックされる

では実際にパラメータをいじって実行してみます。

latency

isEnabledがfalseの状態で実行すると

所要時間 830.59 ms

isEnabledがtrue, minLatencyを1000ミリ秒で実行。

{"isEnabled": true, "failureMode": "latency", "rate": 1, "minLatency": 1000, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404, "diskSpace": 100, "blacklist": []}

所要時間 2031.38 ms

所要時間が伸びましたね。1000ミリ秒のレイテンシ設定が効いています。

exception

failureModeをexceptionにして実行します。

{"isEnabled": true, "failureMode": "exception", "rate": 1, "minLatency": 1000, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404, "diskSpace": 100, "blacklist": []}

関数の実行は失敗します。

パラメータのexceptionMsgに設定した Exception message! が出力されていますね。

blacklist

failureModeをblacklistにして実行します。 s3とdynamodbへの接続をブロックするとしたら、以下の設定になります。

{"isEnabled": true, "failureMode": "blacklist", "rate": 1, "minLatency": 1000, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404, "diskSpace": 100, "blacklist": ["s3.*.amazonaws.com", "dynamodb.*.amazonaws.com"]}

関数自体は成功しましたが、 ログにネットワークを遮断したとの出力がありました。

2020-02-19T04:45:20.394Z    bbeff927-ee3e-43f7-bc69-f5db844caba7    INFO    Intercepted network connection to {backet名}
2020-02-19T04:45:20.435Z    bbeff927-ee3e-43f7-bc69-f5db844caba7    INFO    Intercepted network connection to dynamodb.us-east-1.amazonaws.com

関数がエラーになると思っていましたが、成功しましたね。

今回使用したサンプル関数は、s3とdynamodbに書き込みをしています。 関数は成功したのに書き込みができていない状況を作れるのだと理解しました。 関数内で正しくエラーハンドリングを行なわないといけないことがわかります。

diskspace

failureModeをdiskspaceにして実行します。 lambdaのtmpディレクトリの制限は512MBなので、512MBとして設定してみます。

{"isEnabled": true, "failureMode": "diskspace", "rate": 1, "minLatency": 1000, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404, "diskSpace": 512, "blacklist": []}

何度か実行して、同じコンテナ内で関数が実行されると、ディスクスペースのエラーが発生しました。

statuscode

failureModeをstatuscodeにして実行します。 404を常に返すように statusCodeの値を404にします。

{"isEnabled": true, "failureMode": "statuscode", "rate": 1, "minLatency": 1000, "maxLatency": 400, "exceptionMsg": "Exception message!", "statusCode": 404, "diskSpace": 512, "blacklist": []}

関数自体は成功になっていますが、

{
  "statusCode": 404
}

が返却されました。

まとめ

現行のバージョンでできる5つの障害パターンを試してみました。 いきなり本番環境で実行することは気が引けてしまいますが、開発環境やテスト環境からモジュールを組み込んで確認することは良いアプローチになると思います。

関数が成功したのに期待した結果になっていない といったことが気付くことが出来ますし、対策もしやすくなるのではないでしょうか。

今回はrateを1にして100%障害を発生させましたが、この値を変えて正常と障害の両方が発生する試験パターンも今後試していきたいと思います。

参考