Serverless Ninja Tips "Instant Job Queue" をしっかり紹介してみる

このエントリは、Serverless Advent Calendar 2017Fusic Advent Calendar 2017の5日目となります。

PHPカンファレンスや、Serverlessconf Tokyo 2017でも紹介したServerless Ninja Tips(名前だけかっこいい)ですが、その中で、説明するたびに伝わっていない感がある "Instant Job Queue" について紹介したいと思います。

想定するユースケース「クローラ」

サーバーレスアーキテクチャでWebページのクローラを実装するとします。

まずは、以下のような1つのLambdaファンクション(今回はWorkerと呼びます)を考えるでしょう。

  1. URLを入力として受け取って、URLにアクセスしてHTMLパース、次のURLをリストアップする
  2. リストアップしたURLを次のLambdaファンクションの入力としてinvokeする

これでだいたいクローラとしては動きそうですが、実際に動かすとどうなるでしょうか?

f:id:k1LoW:20171205093634p:plain

無限ループになってしまいます。 さらに、同時実行されるLambdaファンクションはURLをリストアップする度にどんどん多くなり、対象サーバにDoSを仕掛けてしまうことになってしまいます。 これではマズいですね。

  1. 無限ループになる
  2. 同時実行数がどんどん大きくなる

この2つを解決したいと思います。

無限ループを回避する

無限ループを回避するのは簡単です。

URLと同時に深さ( depth ) をLambdaファンクションに与えて、深さが規定に達したら次のURLのリストアップとinvokeをやめて終了すればOKです。

同時実行数を制御する "Instant Job Queue"

次は同時実行数です。

"Instant Job Queue" は、再帰構造になっているLambdaファンクションにおいて、同時実行数を簡易的に制御するためのTipsです。

f:id:k1LoW:20171205093337p:plain

フロー

仕組みとしては以下のようになります。

まず、WorkerだけでなくStarterと呼ぶLambdaファンクションを用意します。そして仕組みの真ん中にSQS(キュー)を配置します。

  1. まずStarterがURLを深さの対をエンキューする
  2. StarterはWorkerをinvoke
  3. Workerはデキューしようとする
  4. Workerはキューがなければ自身を終了する。URLと深さを受け取って、深さが規定に達していても終了する
  5. 深さ++
  6. WorkerはURLにアクセスしてHTMLパース、次のURLをリストアップする
  7. WorkerはリストアップしたURLとインクリメントした深さをそれぞれ対にしてエンキューする
  8. WorkerはWorkerをinvokeして自身を終了する

特徴

AWSのマネージドサービスのみで実現しているので「キュー待ちするWorkerのプロセス管理」などが必要ありません。

また、(本来なら採用したほうが良いであろう)Step Functions よりも安い料金で実現可能です。

具体的な実装

"Instant Job Queue" を実際に組み込んでいる実装として utsusemi があります。

github.com

(utsusemiについてもいつか紹介エントリを書こうと思います)

というわけで

"Instant Job Queue" についての紹介でした。