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

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

Task Queueのタスクがどのように複数のJVMに負荷分散されるか試したよ #appengine

ご存じのとおり、App EngineのJVM(App Server)はクラスタ化されていて負荷分散される――というのがGoogleの説明です。しかし、WebブラウザからApp Engineに届くHTTPリクエストや、Task Queueのタスクによって呼び出されるHTTPリクエストは、実際にどのような感じで複数のJVMに配られるのでしょうか? 

  • どれくらいの量のリクエストが届いたとき、何台のノードに負荷分散される?
  • 負荷分散のアルゴリズムは?(単純ラウンドロビン、sticky session/session affinity、負荷状況に応じた転送など)
  • 新しいJVMの追加や、既存のJVMの削除のタイミングは?

これらについてはGoogleから情報が公開されておらず、謎です。そこでApp Engine利用者の皆さんが実際の経験やテストを通じて情報を交換しながら想像たくましくするしかないわけです。そんな情報のひとつがこれ:

http://blog.stringbuffer.com/2009/04/towards-general-theory-of-jvm-dancing.html

A total of 13285 requests were successfully served during this period. The requests were served by three distinct JVM:s (as identified by Runtime.getRuntime().hashCode()):

    * JVM A served 9273 requests (69.8 % of all requests)
    * JVM B served 4004 requests (30.1 %)
    * JVM C served 8 requests (0.1 %)

この結果を見ると、いちおう負荷分散はされてるみたいですね。しかし上記ページの説明をよく読むと、単純にラウンドロビンされてる訳じゃなくて、連続するリクエストを単一のJVMに集中して転送している振る舞いがわかります。とはいえ、一般的なロードバランサーのsticky sessionやsession affinity設定のように「あるクライアント(IPアドレスとかで識別)からのリクエストは必ず特定のJVMに転送する」って感じでもありません。。う〜むよくわからん。

Task Queueのタスクって本当に分散されてる?

で、twitter上では@WdWeaverさんや@higayasuoさんもこの問題についてつぶやいてて、特に「Task Queueの個々のタスクから呼ばれるリクエストは複数のJVMに分散するか?」という疑問が焦点となりました。そこで手っ取り早くテストすることにしました。私が書いた既存のコードにて、タスクから呼ばれるロジックの最後でJVMランタイムのハッシュコード「Runtime.getRuntime().hashCode()」を取得して、ログに残します。ただ、App Engineのログを手元にダウンロードするのが面倒なので、ログ記録の代わりにUrlFetchを使って私のWebサーバーにHTTPリクエストを飛ばし、URL末尾に上記ハッシュコードを付けました。それで得られたログを加工したのが以下です。ここで、括弧内の整数値がJVMハッシュコードを表します。

[19/Oct/2009:12:10:50 +0900] [4040305] 
[19/Oct/2009:12:10:52 +0900] [9749991] 
[19/Oct/2009:12:10:53 +0900] [5956071] 
[19/Oct/2009:12:10:53 +0900] [23518822] 
[19/Oct/2009:12:10:54 +0900] [1512816] 
[19/Oct/2009:12:10:54 +0900] [9241323] 
[19/Oct/2009:12:10:54 +0900] [32885885] 
[19/Oct/2009:12:10:54 +0900] [14891863] 
[19/Oct/2009:12:10:54 +0900] [2168094] 
[19/Oct/2009:12:10:55 +0900] [23469803] 
[19/Oct/2009:12:10:55 +0900] [9460493] 
[19/Oct/2009:12:10:55 +0900] [11819261] 
[19/Oct/2009:12:10:55 +0900] [16723022] 
[19/Oct/2009:12:10:55 +0900] [26422362] 
[19/Oct/2009:12:10:56 +0900] [32885885] 
[19/Oct/2009:12:10:57 +0900] [26422362] 
[19/Oct/2009:12:10:58 +0900] [23469803] 
[19/Oct/2009:12:10:58 +0900] [5956071] 
[19/Oct/2009:12:10:58 +0900] [9749991] 
[19/Oct/2009:12:10:59 +0900] [1512816] 
[19/Oct/2009:12:11:00 +0900] [25885348] 
[19/Oct/2009:12:11:00 +0900] [25281697] 
[19/Oct/2009:12:11:01 +0900] [9241323] 
[19/Oct/2009:12:11:05 +0900] [4040305] 
[19/Oct/2009:12:11:06 +0900] [1512816] 
[19/Oct/2009:12:11:06 +0900] [14891863] 
[19/Oct/2009:12:11:07 +0900] [25885348] 
[19/Oct/2009:12:11:07 +0900] [11819261] 
[19/Oct/2009:12:11:10 +0900] [4040305] 
[19/Oct/2009:12:11:11 +0900] [25281697] 
[19/Oct/2009:12:11:12 +0900] [9241323] 
[19/Oct/2009:12:11:15 +0900] [25885348] 
[19/Oct/2009:12:11:17 +0900] [9749991] 
[19/Oct/2009:12:11:17 +0900] [23469803] 
[19/Oct/2009:12:11:20 +0900] [11819261] 
[19/Oct/2009:12:11:23 +0900] [26422362] 
[19/Oct/2009:12:11:25 +0900] [11819261] 
[19/Oct/2009:12:11:30 +0900] [25281697] 
[19/Oct/2009:12:11:30 +0900] [23469803] 
[19/Oct/2009:12:11:32 +0900] [11819261] 
[19/Oct/2009:12:11:33 +0900] [25885348] 
[19/Oct/2009:12:11:36 +0900] [9460493] 
[19/Oct/2009:12:11:37 +0900] [9241323] 
[19/Oct/2009:12:11:40 +0900] [11819261] 
[19/Oct/2009:12:11:42 +0900] [25281697] 
[19/Oct/2009:12:11:46 +0900] [4040305] 
[19/Oct/2009:12:11:49 +0900] [26422362] 
[19/Oct/2009:12:11:51 +0900] [32885885] 
[19/Oct/2009:12:11:54 +0900] [4040305] 
[19/Oct/2009:12:11:56 +0900] [25885348] 
[19/Oct/2009:12:12:00 +0900] [11819261] 
[19/Oct/2009:12:12:02 +0900] [32885885] 
[19/Oct/2009:12:12:06 +0900] [9460493] 
[19/Oct/2009:12:12:08 +0900] [4040305] 
[19/Oct/2009:12:12:12 +0900] [9241323] 
[19/Oct/2009:12:12:13 +0900] [26422362] 
[19/Oct/2009:12:12:19 +0900] [9460493] 
[19/Oct/2009:12:12:24 +0900] [4040305] 
[19/Oct/2009:12:12:24 +0900] [26422362] 
[19/Oct/2009:12:12:28 +0900] [14891863] 
[19/Oct/2009:12:12:30 +0900] [9749991] 
[19/Oct/2009:12:12:33 +0900] [9241323] 
[19/Oct/2009:12:12:35 +0900] [9460493] 
[19/Oct/2009:12:12:37 +0900] [14891863] 
[19/Oct/2009:12:12:39 +0900] [26422362] 
[19/Oct/2009:12:12:44 +0900] [4040305] 
[19/Oct/2009:12:12:51 +0900] [9241323] 
[19/Oct/2009:12:12:56 +0900] [23469803] 
[19/Oct/2009:12:12:56 +0900] [32885885] 

で、これをハッシュコードごとに集計したのがこちら:

[11819261]  7
[14891863]  4
[1512816]  3
[16723022] 1
[2168094]  1
[23469803] 5
[23518822] 1
[25281697] 4
[25885348] 5
[26422362] 7
[32885885] 5
[4040305] 8
[5956071] 2
[9241323] 7
[9460493] 5
[9749991] 4
総合計	69

このデータから分かること:

  • 69のタスクが16のJVMに負荷分散されてる。そこそこ均等に配られてる
  • 最大5タスク/sくらいは捌けている(設定は9/s)

もっとも、今回テストに使った環境は開発作業に使っているため、Task Queueによる負荷がちょくちょくかかっており、あらかじめ複数のJVMが立ち上がっていた可能性が高いです。

ところで、タスクで呼ばれるHTTPリクエストのソースIPは「0.1.0.1」とか「0.1.0.2」とかいう怪しいアドレスになります。同じApp Server内から呼ばれてるように見えますね。これは「リモートのTask Queueサービス」→「App Server内のエージェントみたいなの?」→「Webコンテナ」って感じで呼んでるような気がします。

追記:@WdWeaverさんによるApp Engineスケーラビリティ考察

http://www.slideshare.net/WdWeaver/gaej