この記事はLCL Advent Calendar 2021 - 15日目です。
バックエンドエンジニアの高良です。
LCLへの転職を機に沖縄から上京して早2年、地元と段違いの寒さにも段々と慣れてきました。
ここ最近ではRailsでの開発に加え、インフラ周りのちょっとした調整などの作業をすることも増えてきました。
その中で1点、実装方法の調査時に手間取った箇所があったので、解決のポイントを紹介しようかと思います。
SQS(FIFO)と連携しているLambdaのスケールアウト
現在海外航空券では、SQS(FIFO)+Lambdaが連携したバッチジョブが動いています。
こちらは1日1回の実行としているのですが、条件によっては実行時間が1日を上回ってしまい、必要な処理が1日で完了しきれないという問題が発生しました。
この時Lambdaは1台のみで稼働していたため、Lambdaインスタンスの台数を増やし並列で処理を実行させることで1日以内に処理を完了できるようになる想定でした。
そのため、並列で起動できるLambdaインスタンス数の設定(Reserved Concurrency)を増やせば自動的にスケールアウトしてくれるものかと考えていました。
しかしFIFOキューを使用している場合、その設定だけではスケールアウトせず、LambdaのReserved Concurrencyに加えてFIFOキューで用いられるメッセージグループIDの調整も必要ということが分かりました。
メッセージグループIDとは
FIFO(First in first out = 先入れ先出し)のルールを保つために必要な概念です。
エンキュー時にユーザー側で各メッセージごとに固有のIDを付与しておき、デキュー時には同一のIDを持つメッセージ内で先入れ先出しのルールが適用されるという仕組みになっています。*1
メッセージグループIDとLambdaの同時実行数の関係性
結論から言うと、同時実行可能なLambdaインスタンス数 <= メッセージグループIDの数となります。 *2
例えば下記の図のように、メッセージグループIDを1つのみに設定していた場合、同時に実行できるLambdaインスタンスの数もMAX1台となります。
この状態だとLambdaのReserved Concurrencyの数値をいくら増やそうが、Lambdaインスタンスが1台から増えることはありません。
そのためLambdaを2台並列で動かすには、下記のようにメッセージグループIDも2種類以上にしておく必要があります。
このような仕様になっている理由として、一つのメッセージグループIDに対してコンシューマが2つ以上ある場合、先入れ先出しの制御が複雑になりそうな事が原因なのかもしれません。
FIFOキューを使いつつコンシューマのLambdaを並列実行させたい場合は、メッセージグループIDの割当について考慮した実装にしておきましょう。
注意点として、異なるメッセージグループIDを持ったメッセージ同士間では先入れ先出しのルールは保証されなくなります。
そのためメッセージの処理順序を考慮しつつ並列処理数も増やしたい場合は、この点を考慮した設計にしておく必要があります。
今回は説明を省きますが、公式の解説ではメッセージグループ毎の細かい処理順について説明されているので、そちらを参考にしつつ実際に動作確認してみるのが良さそうです。
採用情報
LCLでは開発メンバーを募集中です! カジュアルな面談からでも可能なので、ご興味がある方は気軽に応募してください!