Netty Projectは7月,Netty 4の最初のバージョンをリリースした。おもにガベージコレクションのオーバーヘッドを削減することによって,大幅なパフォーマンスの向上を実現している。TwitterはNetty 4を組み込むことで5倍のパフォーマンス向上を実現したが,いくつか問題もあった。
Netty Projectを立ち上げたTrustin Lee氏が,Twitterのソフトウェアエンジニアと共同でネットワークアプリケーション用フレームワークの開発を始めたのは,2003年のことだ。最初のリリースは2004年7月に公開された。プロジェクトのホームページではNettyについて,"高パフォーマンスを維持するプロトコルサーバおよびクライアントを迅速に開発するための,非同期のイベント駆動ネットワークアプリケーションフレームワーク" である,と説明している。
Twitterでは多くの場所でNettyを使用してネットワーク機能を実装している,と "Netty 4 at Twitter: Reduced GC Overhead" にLee氏は書いている。
- 当社のプロトコル非依存のRPCシステムであるFinagleは,トランスポート層をNetty上に構築しています。このシステムはSearchなど,大部分のサービスの実装で内部的に使用されています。
- 当社独自のスプーンフィーディング(spoon-feeding)リバースプロキシであるTFE (Twitter Front End)では,一般向けのHTTPおよびSPDYトラフィックの大部分をNettyで提供しています。
- Cloudhopperは,全世界の数百というモバイルキャリアに対して,Nettyを使って毎月数十億のSMSメッセージを送信しています。
Reactorパターンを実装したNettyは,Play Frameworkのコア部分でも使用されている。PlayやGrailsといった多くのWebフレームワークはWARレスのWebアプリを採用することで,ベースとなるHTTPサーバとのより強固な統合を実現している。Nettyのようなサーバを内部的に使用することで,非同期プログラミングは極めて簡単なものになる。非同期プログラムと非ブロックI/Oは,Reactive Manifesto にとして中核のテクニックだ。この新たなパターンについては,InfoQでも "注目を集めるリアクティブプログラミング" という記事にしている。
Netty 3では,I/Oイベントを表すためにJavaオブジェクトを使用していた。その点について,Lee氏は次のように言う:
この方法はシンプルですが,当社のような規模においては大量のガベージを発生させることにもなります。Netty 4新リリースでは,これまでの短命なイベントオブジェクトに代えて,寿命の長いチャネルオブジェクトのメソッドを使用してI/Oイベントを処理するように変更されました。プールを使用する専用のバッファアロケータも用意されています。
... Netty 3では新たなメッセージを受信したり,あるいはリモート側にメッセージを送信すると,その都度ヒープバッファが生成されています。そしてこの新たなバッファそれぞれに ‘new byte[capacity]’ が実行されるのです。このように生成されたバッファはGC圧力を高め,メモリ帯域を消費します - 新たにアロケートされたバイト配列毎が安全のためにゼロ埋めされることが,メモリ帯域を消費しているのです。しかもゼロ埋めされた配列はほとんどの場合,後に実際データが詰められますから,同じ量のメモリ帯域を再び消費することになります。もしJava仮想マシン(JVM)にゼロを埋める必要のない配列を新規生成する方法があれば,メモリ帯域を半分に削減することができるはずです。しかし今のところそのような手段はありません。
Netty 4ではイベントオブジェクトの生成に代えて,さまざまなイベントタイプを扱うことのできる,より粒度の小さなAPIを定義している。また,新たなバッファプール実装として,jemallocのピュアJavaバージョンも装備している (これはFacebookでも使用されている)。これらによって,バッファを0で埋めるというメモリ帯域の無駄はなくなったが,GCによって管理されない部分であるため,リークには注意が必要だ。ハンドラがバッファのリリースを忘れていると,メモリ使用量が無制限に増大することもある。
これらの変更はNetty 3と互換性を持たないが,バッファの生成と回収の速度は5倍になる。
Lee氏によると:
私たちはNetty 3と4をそれぞれを使用して構築したechoプロトコルサーバを比較しました (echoは非常にシンプルで,ガベージがプロトコルではなくNettyのフォールトによって生成されたものと見なすのに十分です)。これらのサーバそれぞれに対して,分散配置したechoプロトコルクライアントから16,384の並列的な接続を行い,256バイトのペイロードをランダムに送信します。ギガビットイーサネットがほぼ輻輳するまでこれを繰り返したのです。
このテストの結果,Netty 4は:
- GCによる停止回数が1/5 – 45.5回/分 : 9.2回/分
- ガベージ生成が1/5 – 207.11MiB/秒 : 41.81 MiB/秒
氏はNetty 4をTwitterに適用する上でいくつかの障害があったことに触れている。具体的にはバッファリークとコードの複雑さだ。同プロジェクトではHTTP/2や非同期DNS名前解決,HTTPとSOCKSプロキシサポートなど,クライアント側の機能なども取り込みたいと考えている。
Yahoo Engineeringにも同じような記事があり,Nettyが同社のStormクラスタのスピード倍増に寄与した状況が紹介された。その記事 "Making Storm fly with Netty" では,Bobby Evans氏が次のように述べている:
Yahooでは自社開発したシステムを使用していましたが,NettyをStormクラスタの既定メッセージレイヤとする前には,現在のデフォルトであるzeromqと比較した数値を取得しておく必要がありました。そのためには,Stormのメッセージレイヤを明確に凌駕する証拠としてのベンチマークが必要でしたので,それを書きました。Stormの異なるBoltとSpoutの間でメッセージをプッシュする速さを確認するための単純な瞬間速度計測テストで,複雑度の異なる複数のトポロジをローンチした上で,固定サイズのメッセージを送信できるようになっています。
Evans氏は(リソースが競合しない)小さなテストを使用して,Nettyがzeromqより高速(40%~100%)であることを示した。より規模の大きなテストを実施した際にパフォーマンス上の問題が発生したが,スレッド数を制限することで解決できたという。
Nettyのデフォルト設定は,たとえノードがひとつだけだったとしても,小さなメッセージを多数扱うのには適切ではありません。しかしスレッドをひとつに制限することで,ネットワークが再び輻輳するまでの間に,zeroqよりも1秒当たり111%から85%多いメッセージを取得することが可能になります。
氏によるとNettyは現在,YahooのStormクラスタのデフォルトになっている。
Netty 4の改善は,多くのオープンソースプロジェクトにメリットがあるだろう。フレームワークに関連するものとして挙げられた一覧の中には,AkkaやApache James,HometQ, Vert.xなど,多数のプロジェクトの名前が見える。Netty 4について詳しくは netty.ioあるいはLee氏のブログ記事を参照してほしい。