JAWS-UG 朝会にてLTをやった内容をもうちょい深掘りしてみました。
Lambda の処理が止まらなくなったので、やったことをまとめてみます。
やろうとしていたこと
KinesisからのストリーミングデータをLambdaで受け取り、よしなに処理したあとに別サービスへとAPI連携をしていこうとするつもりでした。
CloudWatch にずっと出てくるログを見て・・・
メッセージを見るために何度かみているのですが、どうもずっと動いているようでした。
最初は継続しているのかな?と思いながら見ていたのですが、1分で出ている量がおかしいと思い、対処していくことにしました。
まずは止めにかかる
Lambda を一時停止させる
兎にも角にも Lambda は停止しないと無限課金されるので一旦処理を止めます。
止める方法は対象の関数から「同時実行」→「編集」から「同時実行の予約」の数を 0 に設定します。
これで処理は一旦止められたのでそこから見ていきます。
同時実行の設定を戻すと当然処理が再開されますので、一時しのぎです。
LambdaとKinesisの連携を止める
Lambdaの対象関数の画面からトリガー→無効化で連携を切ります。後述しますが、Kinesisから情報が来続ける限りデータの処理をしようとしちゃうので止めます。
パラメータをチェックしていく
普段意識せずに見ていたパラメータについてせっかくなので深掘りしながら見ていこうと思います。
Lambda のモニタリング項目
デフォルトで表示されているものです。
- Invocations
関数コードが呼び出された回数で、成功失敗問わずここにカウントされていきます - Duration
関数コードがイベントの処理に費やした時間 - Error count and success rate
エラーの発生回数。例外処理の回数もここに含みます - Throttles
スロットリングされたリクエスト数 - IteratorAge
ストリームから読み取る場合のイベントのレコード最後の所要時間 - Concurrent executions
イベントを処理しているインスタンスの数
まず今回は明らかに処理の時間が増えたこと、エラーの割合が大幅に増えていました。
思いつくのは書いたコードの中身がおかしく、それをずっと処理し続けていたことだと思いました。
にしてもそれまできちんと動いていたのと、エラーも無視してたのでなんでだろうって感じでしたが・・・。
原因と反省
今回やらかしたのは関数内にてループ処理を行ったこと。一応breakも入れて大丈夫なようにしたのですが、それでも引っかかってしまったようです。
どうやらLambdaのアンチパターンとして再帰パターンを引き起こすようなものを入れてはいけないとのことでした。
いくらbreak文を入れていたとはいえ、forループを入れたものを使うのは危険かもしれないですね(単純に自分のコードがだめだめだった可能性があります)
また、Kinesisは情報の保持期間の間は無事に送られるまで繰り返し送ろうとします。つまりLambdaが処理できるまでずっと続くという仕様でした。
Kinesisのデータ保持期間は最低でも24時間。Lambdaの最大実行時間が15分だから大丈夫と高をくくっていたら新規で処理を開始してたので結局続きました・・・。
Step functionsとかを使うことでそれらは回避できるようですし、CloudWatchでの検出が出来るように設定をしておけばもっと早く気付けたし回避できたのではないかと思ってます。
結局どうしたか
やらかした部分のコード修正
根本的に見直しました。テストとはいえ、下手に動かすのは良くなかったですね。それまで動いていたのはたまたまで本来の動きを取り戻しただけでしょう・・・。
Lambdaの非同期呼び出し変更
Lambdaの動きを制御する場所の一つに「非同期呼び出し」の部分があります。デフォルトではイベントの最大実行時間は6時間、再試行は2回となっています。
処理自体に問題が無いなら最大実行時間は少なくしてもいいですし、再試行の回数も1回とかにしてもいいと思います。
おわりに
今回はたまたま目視で早めに確認できたのでそこまで大きなトラブルにならずにすみました。
でも調べているとむちゃくちゃ課金されているという例もあるので、CloudWatchでの検出もちゃんと出来るようにしとくのがいいなと感じました。
監視って甘く見てるときにサボると痛い目みるなと思いました。皆様も気をつけましょう。
参考
エラー処理と AWS Lambda での自動再試行
Lambda アプリケーションのモニタリングとトラブルシューティング
身に覚えのない170万円の請求が……AWSの運用管理で起きた“4つのしくじり”
Operating Lambda: イベント駆動型アーキテクチャにおけるアンチパターン – Part 3
10日間 で AWS Lambda 関数を 28億回 実行した話