Nettyでab書いてみた
JBoss Advent Calendar 2011の27日目のエントリです。Nettyは非同期ネットワークアプリケーションフレームワークです。現在、NettyはJBossプロジェクトから移動中であり、JBoss NettyではなくNettyプロジェクトとして http://netty.io/ というサイトで独立することになります。
さて、Nettyを使ってなんか書いてみよう、と思ってとりあえずabを書いてみました。本家abは結果報告が詳細ですが、自分で書いたものは平均レスポンスタイム、成功と失敗リクエスト数くらいしか出ないものです。コードは以下に置いてありますが、ザラっと書いたものなのでかなり荒いです。
https://github.com/nekop/java-examples/tree/master/jab
Nettyのプログラミングモデルですが、基本的にはSimpleChannelHandlerを実装したら終わりです。channelConnected()やmessageReceived()といったイベントに対応したメソッドがあるのでそこに処理を書けば良いです。かんたん。
http://netty.io/docs/stable/api/org/jboss/netty/channel/SimpleChannelHandler.html
サーバはプロセス数100にしたnginxで、ベンチマーク対象データはddで100kbのファイルを作りました。
$ dd if=/dev/zero bs=1024 count=100 of=100kb.dat
同時接続数800、リクエスト数10000で計測しています。
結果
実装 | 平均レスポンスタイム |
---|---|
ab | 130 |
HttpURLConnection | 82 |
Netty Old IO | 180 |
Netty New IO | 190 |
結果の平均レスポンスタイムをそのままパフォーマンスの指標として解釈しないほうが良いです。
などなどの理由で、この結果はNetty遅い、とかそういう類のデータを示すものではありません。
HttpURLConnection実装
ExecutorとHttpURLConnectionでストレートに実装して、終了条件はリクエスト数のCountDownLatchを使っています。1分くらいで書けますね。
Netty実装
Netty実装は今の時点ではあまりきれいとは言えない出来です。問題はNIOで、HttpURLConnection実装のように「スレッド数 == 同時接続数」とはならないので、1リクエスト終了時に次のリクエストが飛ぶように、などの工夫が多少必要になってきます。しかし、状態はChannel毎に作成されるChannelHandlerのインスタンスフィールドなどに保持できてカプセル化できますし、イベントメソッドが分かれていて見通しも良いので、後から変更するのはそれほど面倒ではないです。
Old IOとNew IOがcreateChannelFactory()メソッドだけで切り替えられるように出来た、というのは素晴らしいところ。
Netty NIO
同時接続数800ですが、NIOを利用しているので800スレッドを使う必要はありません。今回は20スレッドで走らせた結果です。HttpURLConnectionとNetty Old IOでは800スレッドのExecutorが必要です。NIOはエコで地球にやさしい。
あと、同時接続数とかリクエスト数をあげていくと、channelOpen()とchannelClosed()だけ呼ばれる不思議なChannelが発生します。channelConnected()かexceptionCaught()のどちらかが呼ばれそうなものですが、そうならないパターンがあるようです。後で調べます。
どうでもいいこと
なぜかabの-cに700以上指定するとContent-Lengthを193バイトと誤認識して全部Lengthエラーだと報告される。なんだろう。