前回に引き続き、Kinesisネタです。今回は、前回紹介したとあるコンシューマアプリケーションの運用で、タイトルにもある通り24時間稼働ではないユースケースでの運用で少しハマった点があるので書き記します。
ダウンタイムについて
今回のビジネスのユースケースでは、午前8時〜午後8時までのようにデータの処理は24時間する訳ではなく、ダウンタイムが設けられています。
コンシューマを実行しているインスタンスはオートスケーリンググループにより、ダウンタイム中はTerminateされ、翌日新しくインスタンスが立てられます。
前提
- コンシューマアプリケーションはKCLの1.xを使っている
- systemdによってサービス登録されている
- 使用しているOSはAmazon Linux 2
ハマった点: 最後のチェックポイントがうまく記録できない
今回のコンシューマアプリケーションでは、 processRecords
による定期記録 (メソッド内の全レコードを処理した後に記録) と requestedShutdown
による最終的な記録を行っているのですが、ダウンタイム直前にプロデューサーから大量のレコードがPushされると、うまくチェックポイントを記録できなくなりました。
原因としては、 requestShutdown
が呼ばれるのが、 processRecords
の処理が終わった後だからのようで、先述の通りダウンタイム直前に大量のレコードがPushされると、EC2からのシャットダウン時のsystemdからのSIGTERMをタイムアウト前に処理できず、結果最後の processRecords
で処理したレコード分が丸ごと記録できないと言う事態が起きていました。
翌朝起動した時にその大量のレコードを再度処理する事になる
大量のレコードが最後のレコード処理に来ると、最後のチェックポイントが記録できずにアプリケーションが終了する為、翌朝8時に起動した際にこれらのレコードをもう一度処理する事になってしまいます。
レコード処理自体は冪等性をもたせる必要があるため、重複処理事態は問題がないのですが、MillisBehindLatestが増加し、本来8時から処理しなければならないレコードの同期ずれが起きる事態となっていました。
今回、同期ずれ10分程度は許容できるのでそこまで問題はないですが、不要な同期ずれは極力なくしたいと思い、いくつか対応策を検討しました。
systemdの終了タイムアウトを伸ばした (未解決)
デフォルトでは90秒であるタイムアウトの時間を試しに10分程度伸ばしてみました。
しかし、これは解決しませんでした。ログを見ると、10分待つ事なくインスタンスがTerminateになっており不思議に思っていたのですが、AWSのドキュメントに普通に書いてありました。
Amazon EC2 コンソール、コマンド行ツール、または Amazon EC2 API を使用してインスタンスを再起動する場合、インスタンスが 4 分以内に完全にシャットダウンしないと、ハードリブートが実行されます。
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-reboot.html
DynamoDBのデータを定期削除するようにした (解決)
解決策として、最終的にチェックポイント記録のバックエンドとして使っているDynamoDBのデータをダウンタイム期間中にLambdaで全部削除し、KCLワーカーの初期ポジションを LATEST
にする事で、この問題を解決しました。これにより、最後のレコード群はチェックポイントが記録されませんが、翌朝起動時にはワーカーが初期化された後に流れてきたレコードから処理されるようになります。
また、EC2のハードリブート問題はまだ解決していませんが、今回はダウンタイムに差し掛かっているレコードはビジネス要件的にもれなく処理する必要があると言う訳ではなかったので、今回の対応策に落ち着きました。