目的
Amazon LambdaとKinesis Stream構成の初歩的な「あるあるトラブル」で時間と労力を無駄にしないことです。
想定読者
下記のいずれか
- これから初めてAmazon LambdaとKinesis Streamを使おうとしており、それぞれのサービスについて概要と基本的な動かし方は知っているが、運用経験は無い人
- 上記に当てはまる人に対して、基礎的な(バッド)ノウハウを共有したい人
かつ
- Lambda FunctionでJavaのコードを使いたい人
です。
前提
Kinesis Streamをイベントソースとして、Lambda FunctionでJavaのコードを動かすこと。
本題
自分が遭遇したトラブルの原因別に問題と対策(唯一解ではない)をまとめてみました。
Lambda Functionのメモリ割り当て不足に起因する問題
- Javaで実装したハンドラーが実行されない
マネジメントコンソールからメモリ割り当て量を選択する仕組みが実行プラットフォームを考慮していないため、動作が現実的ではない構成が選べてしまいます。
JavaはJVM立ち上げのためにある程度のメモリを必要するため、最低限でも256MBは割り当てないと動きません。
最小構成である128MB割り当てで実行し、エントリーポイントにすら辿り着いていないログを見て唖然とするのはみんなが辿った道?です。
改修したらclassファイル増えて必要なメモリ量が増えた結果、突然動かなくなったという話もあります。
割り当てメモリをケチるのは後回しにしましょう。
Lambda Functionのリトライ制御不足に起因する問題
- 同一データに対する処理の重複
- データロスト
イベントハンドラーが例外をスローした場合、Kinesis Streamから再度同じデータ列を最初から読み込む形でハンドラーが再実行されます。
例えば、バッチサイズを10にしていて、Kinesis Streamから読み込んだ5件目のデータの処理中に例外をスローしたとすると、リトライによって1件目から4件目までは同じ処理が2回実行されることになります。
さらに、5件目のデータそのものが不正で、確実に例外をスローするような場合、延々とリトライが繰り返されることで6件目以降のデータに対して処理が実行されません。これは放置するとデータの生存期限(デフォルトで24時間)を過ぎるまで続き、場合によってはデータロストに繋がります。
例外発生を想定してtry~catchするのは当然として、エラー対応のポリシーを定めて関係者で合意すると良いでしょう。
エラー対応のポリシー決定に際しては、リトライによる自動復旧がどの程度見込めるか否かでエラー原因を分けると良いです。
データロストや重複をある程度は許容できる状況で一番単純なポリシーは「不正データは読み捨てて存在しないものとして扱い、関連システムの障害によるエラーは復旧までひたすらリトライするのに任せる」というものだと思っています。
これは同一データに対する処理の重複もデータロストも完全には防げない分、設計と実装のコストを少なく抑えながら、正常系の動作継続を優先できます。