スティルハウスの書庫の書庫

はてなダイアリーで書いてた「スティルハウスの書庫」を移転してきました。

Task QueueはMapReduceの夢を見るか

いまコーディング中の案件で、Task Queueにぴったりハマる要件があったので、飛びついてみました。

  • 課題:Datasource上の大量のデータをクライアントにダウンロードしたい。30秒内では終わらないので複数のリクエスト/レスポンスに分割してダウンロードする実装にした。しかしデータ量によっては何10分もかかってしまう。
  • 原因:データ量の多さもあるが、それを取得するためのDatastoreのクエリ、および関連エンティティの取得にもっとも時間がかかっている
  • 書こうとしているソリューション:クエリと関連エンティティ取得をTask Queueのタスクに分割して並列処理(map)し、取得したデータを集約(reduce)してクライアントに渡す

…んん、これってMapReduceではないですか。1つのリクエストでは重い処理は、たくさんのタスクに細切れにして、キューにどんどん入れる。App Engineはデフォルトで負荷分散クラスタになっているから、もし1台のサーバーで間に合わないほどキューにタスクがたまれば、タスクは自動的に複数サーバーで分散処理されます(スケールアウトするタイミングとかよく分からないけど)。これを数10ノード規模で実行すれば、やっていることはMapReduceとあまり変わりません。Task QueueがあればMapReduceはなくてもいい気がしてきました(MapReduceでコード書いたことないので分からないけど)。いろいろ応用できそうで妄想してしまいます:

  • 動画エンコーディングとか変換とかをたくさんのタスクに分割して並列処理
  • Google Mapの地図表示みたいな処理も、個々の領域を個別のタスクで並列描画
  • インクリメンタル検索等もたくさんのタスクへ並列処理すればさくっとレスポンスが返ってウマー
  • (今回私が試してるのもこれですが)ユーザーがこれから必要としそうなデータをたくさんのタスクで並列でプリフェッチしてmemcacheに入れておく
  • 集合知プログラミングとかデータマイニング、BIみたいな、とにかくCPU/ディスクをぶんまわすような処理もたくさんのタスクで並列処理
  • もちろんこれまで面倒だったエンティティ一括削除とか鬼早に

などなど、ちょっと考えただけでもわくわくしますね。

Task Queueをちょっと使った感想

しかもTask Queueは使い方がすごく簡単。なにも高尚な仕組みはありません(クラウドの中ではトラフィックシェーピングとか複雑なことやってるだろうけど)。

  • WebHookだから、いつも通りHTTPリクエストに対するアクションの形で書けばよい
  • 処理対象のデータはmemcacheかDatastoreに入れておいて、そのキーをWebHookで呼ばれるURLのパラメータに入れておく
  • ロジックの書き方はActionScriptJavaScriptイベントハンドラを書くのと同じ。ひとつのロジックを細切れにして、非同期実行する

まだ完成していないが、上記課題のコードの半分くらいはTask Queue実装に置き換えることができました。もう少しです。

現在のTask Queueの課題

しかし、現在のTask Queueは「experimental」扱いであり、いくつか難点があります。まず、「キューに追加できるタスクの総数が最大10万件/1日(課金対象アプリの場合)」という制限です。

http://googleappengine.blogspot.com/2009/09/app-engine-sdk-125-released-for-python.html

With the 1.2.5 release, we are increasing the daily quota for Task Queue insertions to 100K for billing-enabled apps.

(ちなみに、Task Queueドキュメントの方はちょっと古くて、1万件/日と書いてある)

実運用を考えると、これは少ないです。そういう要望はMLでもあがっていて、個別相談で制限を引き上げてくれそうなGoogleからの返答もあります。

もう一つは、Task Queue APIが正式パッケージに含まれていない点。

http://code.google.com/intl/en/appengine/docs/java/taskqueue/overview.html#Status_of_the_Task_Queue_API

The App Engine Task Queue API is currently in an experimental state, release as an App Engine Labs feature. We are eager to get your feedback so that we may improve the API. During this initial, experimental phase, the API will be located under the App Engine Labs package:

com.google.appengine.api.labs.taskqueue

3つめの制限、というほどでもないが、並列処理の規模には制限があります。そもそも現在のApp Engineでは、1アプリあたりの最大同時処理数は30に制限されています。

http://code.google.com/intl/en/appengine/docs/java/runtime.html#Quotas_and_Limits

An application can process around 30 active dynamic requests simultaneously. This means that an application whose average server-side request processing time is 75 milliseconds can serve up to (1000 ms/second / 75 ms/request) * 30 = 400 requests/second without incurring any additional latency. Applications that are heavily CPU-bound may incur some additional latency in long-running requests in order to make room for other apps sharing the same servers. Requests for static files are not affected by this limit.

上述のとおり、かりに1リクエストに1秒かかると、30リクエスト/秒。これでは大規模並列処理って感じではないです。しかしGoogle I/Oでも回答があったように、この制限は個別相談で外してもらえるらしいです(でないとOpen for Questionsのようなスケーラビリティは出ない)。

と、いろいろ現実問題はありますが、しかしWeb Hookみたいな簡単な仕組みだけででっかいクラスタ上での並列処理を堪能できるなんて、クラウド始まったなという感動があります。