何が起きたのか
リアルタイムを実現するアーキテクチャを以下のように組みました
逐一流れてくるデータソース(企業秘密)→Kinesis→Lambda→DynamoDB
データソースにもDynamoDBのデータの双方に書き込みのタイミングのタイムスタンプが入っていました。そのタイムスタンプがずれてたんです!
それも1時間。果てどうしたものか・・・
AWSがヒントを提供していた
この遅延、実はメトリクスで分かったんです。そのメトリクスは
IteratorAge
です。KinesisでもIteratorAgeMillisecondsとしてメトリクスに書かれていました。
このIteratorAgeは
** 読み込んだ時刻と処理時刻の差分
の事のよう。つまり、「入った時間と出る時間の差分」つまり、Kinesis+Lambdaのリアルタイム処理の「遅延」を表していることになると至りました。
「Amazon CloudWatch による Amazon Kinesis Data Streams サービスのモニタリング」
https://docs.aws.amazon.com/ja_jp/streams/latest/dev/monitoring-with-cloudwatch.html
そして答えも提供していた
「Lambda 関数の IteratorAge メトリクスが上がるのはなぜですか ?」
https://aws.amazon.com/jp/premiumsupport/knowledge-center/lambda-iterator-age/
この中に書いてある大事なのは「バッチサイズ」「シャード」「Duration」
バッチサイズ
バッチサイズが小さすぎると、その分多くのlambda起動が必要で、上限数による処理の限界があるのはもちろん、起動時間などのその他の時間も多く発生していまします。秒を争うリアルタイム処理ではこのその他の時間も馬鹿になりません。
シャード
一回に処理できる出口の数。蛇口が多い層がそりゃいいですよねって話。Lambdaの同時実行数が気になるところですが、上限緩和は可能なのでRealTimeの称号に勝るものはありません。
Duration
リアルタイム処理では「1秒間に何データ処理できるか」が大事になります。処理時間が長引けば当然「意秒間に処理できるデータ数」は減っていきます。これは短いに越したことがない
おまけで「Lambdaのバッチウインドウ」
これは時と場合によると思います。「何秒ごとに処理をするのか」といった設定になります。これが
1秒間に入ってくるデータ数>1秒間の処理できるデータ数
となると当然未処理データが溜まっていきますので遅延が発生する結末を迎えます
結局何をしたのか
ここまできて私たちがしたこと
- シャードを1→4に
- バッチサイズを10→100へ
- lambdaのメモリを254MBへ
と変更しました。
最初の設定、リアルタイムを舐めてるとしか言えないレベルの設定でしたねw
これにて通常時はめでたく1秒以内を実現。めでたしめでたし。。。
しかし、これだけでは終わらなかった
このリアルタイム処理、夜の約4時間は停止していたのですが起動直後に大遅延が発生するトラブル発生。
原因は停止直後からのデータ
Kinesisは24時間データを保管しておく設定でした。なので、停止直後から起動直前までのデータがはKinesisに存在していました。。これらから順に処理されていたために、その後の処理が後回しになり遅延が発生。
lambdaの設定を変更
「Maximum age of record (レコードの最大期間)」というTriggerの設定項目があります。
ここがデフォルトでは7日間。このままでした。
これだと、処理対象は「7日前」からになりますので、停止から起動までの4時間は当然処理対象となってしまいます。これが遅延の原因でした。
止まってる期間のリアルタイム処理は処理しないで良い仕様なので、最小値の60秒に設定。1分前のデータしか対象にならないようにしました。
これで晴れて安定稼働
最後に
リアルタイムの処理では当たり前の観点ですが、この点がすべてインフラで設定できてしまうのはさすがクラウドと感心してしましました。
またこれも常識ですが、リアルタイムの処理とはいえ、集計はある程度まとめて行う必要がある(バッチサイズとか)のでアプリの設計も意識しなければならないなぁと感じました
ご静聴ありがとうございました