リモート開発メインのソフトウェア開発企業のエンジニアブログです

24時間稼働でないKinesisストリームの運用で手こずった点

前回に引き続き、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のハードリブート問題はまだ解決していませんが、今回はダウンタイムに差し掛かっているレコードはビジネス要件的にもれなく処理する必要があると言う訳ではなかったので、今回の対応策に落ち着きました。

← 前の投稿

BERTについて勉強したことまとめ (1) BERTとは? その特徴と解決しようとした問題、及び予備知識

次の投稿 →

Scala + Kinesis Client LibraryでKinesisコンシューマーアプリケーションを作る

コメントを残す