Grizzlyフレームワーク

Grizzlyフレームワーク
Non-Blockingソケットと非同期処理に対応した
HTTP等プロトコルハンドラフレームワーク
Learning.sandbox.seasar.org
2006-12-27 栗原 傑享
© 2006 The Seasar Foundation and the Others, All rights reserved.
About Grizzly - とりまく環境 • GlassFishの傘下コンポーネント
– 内包されるWebコンテナの部品
• プロトコルハンドラを作るためのF/W
– NIOのNon-Blockingソケットを活用するF/W
• 最近、java.netのトッププロジェクトへ
– https://grizzly.dev.java.net/
• Grizzlyが採用されているOSSプロダクト
– Jetty6.1
• http://www.mortbay.org/
– AsyncWeb
• http://docs.safehaus.org/display/ASYNCWEB/Home
– JRuby on Rails
• われらが、高井さんのプロジェクト。この先Grizzlyに同梱?
© 2006 The Seasar Foundation and the Others, All rights reserved.
About Grizzly - 守備範囲 • Non-Blockingソケット通信
– Java NIOにて提供されるNon-Blockingソケット(以後、
NBソケット)通信をフレームワーク化して容易に用いるこ
とができるようにしている。
• 非同期処理
– Ajaxや昨今のWeb2.0的アプリケーションで求められる、
超長期トランザクションにNBソケット通信でも対応できる
機能をフレームワーク上に応用実装した。
– さらに、Ajax/Cometの機能をデフォルト提供
• デフォルトHTTP機能
– Grizzlyは専らHTTPのハンドラとして機能が設計、提供さ
れている。
– 2.0計画の中では、ESBエンジンの実装基盤など、非
HTTPもしくはHTTPからさらに発展した今後、汎用のプロ
トコル通信フレームワークとして発展させていく野心があ
るように、説明されている。
© 2006 The Seasar Foundation and the Others, All rights reserved.
Blockingソケット
• NIO以前
– Java.netパッケージのAPIを利用
– Servletコンテナの価値 = このコーディングを隠蔽
ServerSocket server = new ServerSocket(8080);
Socket con = server.accept();
InputStream in = con.getInputStream();
for(int b = in.read(); b != -1; b = in.read()) {
// 読み込み
}
// ロジック実行(Servletの実行など)
OutputStream out = con.getOutputStream();
for(int b = /* 書き出しバイトのバッファ */ ) {
out.write(b);
}
スレッド
サーバソケット
Open
接続 Accept
Blocking
リクエスト
Read
Blocking
ロジック実行
レスポンス
Write
Blocking
•例外処理、コネクションCloseなど省略
© 2006 The Seasar Foundation and the Others, All rights reserved.
接続 Close
Non-Blockingソケット - ソース ServerSocketChannel channel = ServerSocketChannel.open();
channel.socket().bind(new InetSocketAddress(8080));
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_ACCEPT);
while(selector.select() > 0) {
for(Iterator<SelectionKey> it = selector.selectedKeys().iterator; it.hasNext(); ) {
SelectionKey key = it.next();
it.remove();
if(key.isAcceptable()) {
SocketChannel socket = channel.accept();
socket.register(selector, SelectionKey.OP_READ);
} else {
if(key.isReadable()) { /* 読み込み */ }
if(key.isWritable()) { /* ロジック実行、書き出し */ }
}
}
コード例は不完全で、実際に動かすためにはほぼ倍以上の実装量が必要
}
•例外処理、コネクションCloseなど省略
© 2006 The Seasar Foundation and the Others, All rights reserved.
Non-Blockingソケット
省略のためUMLを故意に誤用
ServerSocket
Channel
クライアント
から接続
Socket
Channel
Selector
アプリ
チャネルBIND
スレッド
初期化
登録(ON_ACCEPT)
SelectionKeyに結びつく
Acceptableに設定
isAcceptable ? Yes!
Accept処理
ループ
selectを繰り返す
SocketChannel取得
クライアント
からリクエスト受信
登録(ON_READ)
SelectionKeyに結びつく
Readableに設定
isReadable ? Yes!
Writableに設定
読み込み
isWriable ? Yes!
書き込み
クライアントへ
© 2006 The Seasar Foundation and the Others, All rights reserved.
スレッドに優しい仕組み
• NBソケット
– スレッドの占有の問題を解決する
• ソケット接続を維持(OS機能)、スレッドは適宜解放
• OS機能に「待ちうけ時間」は負担してもらう
• 結果、接続数あたりのスレッドの消費が少ない
• リスク
– 実装が複雑になること -> Grizzlyで解決。
– スケーラビリティをアプリケーション外部(クラスタ
リングなど)で確保するのであれば、Blockingの
ほうが単純なので早いものが作れる
© 2006 The Seasar Foundation and the Others, All rights reserved.
No Apache
• http://weblogs.java.net/blog/jfarcand/archive/2005/06/griz
zly_an_http.html
– But as other Java based HTTP Connector, scalability is always
limited to the number of available threads, and when keep-alive
is required, suffer the one thread per connection paradigm.
Because of this, scalability is most of the time limited by the
platform's maximum thread number. To solve this problem,
people usually put Apache in front of Java, or use a cluster to
distribute requests among multiple Java server.
• 前後の事情も込みで意訳
– (Grizzlyがベースとして採用しているTomcat Coyoteも含めた従来
の)JavaベースHTTPコネクタは、スケーラビリティは常に利用可能ス
レッド数に制限されています。keep-aliveでリクエストされた時は長い
接続単位あたりそれぞれにずーっと1スレッドが費やされ続けます。
そのため、スケーラビリティは多くの場合プラットフォームの最大ス
レッド数に制限されます。この問題を解決するために、普通みんなは
Apache HTTPDをJavaシステムの前に置いたり、たくさんのJavaア
プリケーションサーバをクラスタしてますね。(これは大変な苦労で
す。)
• Grizzlyにより、Apache無しのJavaシステムでOKになる。
© 2006 The Seasar Foundation and the Others, All rights reserved.
Simple Grizzly
package org.ashikunep.iyomante;
import com.sun.enterprise.web.connector.grizzly.SelectorThread;
import com.sun.enterprise.web.connector.grizzly.
standalone.StaticResourcesAdapter;
import org.apache.coyote.Adapter;
Tomcat Coyote のクラス
public class SimpleGrizzly {
public static void main(String[] args) throws Exception {
SelectorThread selectorThread = new SelectorThread();
selectorThread.setPort(8080);
Adapter adapter = new StaticResourcesAdapter();
selectorThread.setAdapter(adapter);
このAdapterを作って設定するの
selectorThread.initEndpoint();
が、想定されているGrizzlyアプリ
ケーションの開発方法。
selectorThread.startEndpoint();
ここで用いているものは、静的な
ファイルを読み出して返すもの。
}
}
これだけで、最低限の機能ながらちゃんと動く
© 2006 The Seasar Foundation and the Others, All rights reserved.
参考: Adapter インターフェイス
package org.apache.coyote;
public interface Adapter {
void service(Request req, Response res) throws Exception;
void afterService(Request req, Response res) throws Exception;
void fireAdapterEvent(String type, Object data);
}
package org.apache.coyote;
public final class Request {
public Response getResponse () {
return response;
}
…
}
package org.apache.coyote;
public final class Response {
public void doWrite(ByteChunk c) {
…
}
…
}
© 2006 The Seasar Foundation and the Others, All rights reserved.
Grizzlyの構造
SelectorThread
ON_ACCEPT
クライアント
から接続
Socket
Channel
Selector
(ACCEPT用)
ON_READ
Pipeline
(Read用)
ReadTask
Pipeline
(Process用)
ProcessorTask
Stream
Algorism
Adapter
ごめんなさい、書きかけです。
登場人物が多すぎ
© 2006 The Seasar Foundation and the Others, All rights reserved.
ユーザー
アダプター
Grizzlyのアーキテクチャ - 用語 • SelectorThread
– NBソケット処理のメインスレッドを隠蔽
– nio.Selector、Pipelineを複数もつ
• (Pipeline)
– Taskを単位として管理するスレッドプール
• Task
– ソケットに対する処理を分割した単位
– (ReadTask)
• ON_READに対する処理、SlectorThreadより実行される
– ProcessorTask
• ON_WRITEに対する処理、ReadTaskより実行される
• Adapter (Tomcat Coyoteより)
– ProcessorTaskより実行される
• (Handler)
– Grizzlyへの高度なカスタマイズを行うイベントハンドラ
– 今のところ、Coyoteとの接続やAsyncの実装に使われるのみで、拡
張ポイントとしてはあまり活用されていない。
© 2006 The Seasar Foundation and the Others, All rights reserved.
Grizzlyのアーキテクチャ - 逆引き -
• 接続処理
– SelectorThread#startEndpoint()で開始
– クライアントからの接続要求に応答
• 読み込み処理
– ReadTaskインターフェイスを実装する
– クライアントから到着するリクエスト電文を読む。
• ビジネスロジック&書き込み処理
– ProcessorTaskインターフェイスを実装
• もしくは、coyote.Adapterを実装。
– リクエスト電文に応じて処理を行う。DBアクセスし
たり、画面遷移したり、応答書き出しをすいる。
© 2006 The Seasar Foundation and the Others, All rights reserved.
SSL対応
• 使ってる例が見当たりません
– JettyもGrizzlyのSSL機能を使ってない?
– AsyncWebもGrizzlyのSSL機能を使ってない?
• コードを読むと
– SelectorThreadの代わりにSSLSelectorThread
を利用するだけのハズ。。。しかし動かない。。。
– ということで、いつかどこかでの、宿題。
• たぶん、WEBコンテナを作るために必要なので近日に
解明するでしょう。
© 2006 The Seasar Foundation and the Others, All rights reserved.
非同期処理
• NBソケットは単一もしくは少数スレッドで多数の接
続を処理する。
– 読み込み、書き込みともに(大抵は)同一スレッドで多数
の接続を処理
– ロジック実行に長時間が経過するアプリケーションだと、
この超ロングトランザクションによってスレッドがいわば
「Blocking」されてしまう
• Task処理をマルチスレッドで実行する
– 特にProcessorTaskの処理
– このあたりの技術をひとまとめに、Grizzlyでは
「Asynchronous Request Processing(ARP)」と呼ぶ。
• 基本的に、ここに踏み込むことはあまりない。
– Cometの実装など、プロトコル処理の根底に関わる仕組
みで、かつ非同期実行がその解決策であるときに利用
© 2006 The Seasar Foundation and the Others, All rights reserved.
ARP
• 新たに、登場人物
– AsyncFilter, AsyncHandler, AsyncExecutor
SelectorThread st = new SelectorThread();
st.setPort(8080);
st.setAdaptor(new StaticResourcesAdapter());
AsyncHandler handler = new DefaultAsyncHandler();
handler.addAsyncFilter(new AsyncFilterImpl());
st.setAsyncHandler(handler);
st.setEnableAsyncExecution(true);
st.initEndpoint();
st.startEndpoint();
class AsyncFilterImpl implements AsyncFilter {
public boolean doFilter(AsyncExecutor executor) {
…
ここで何をやるのかが、大抵ネタが無い。必要なモノは
return false;
AsyncExecutorが実行時コンテキストとしていろんなものを
提供してくれているので、それを使ってプログラミング
}
}
© 2006 The Seasar Foundation and the Others, All rights reserved.
Comet
•
Cometとは
– CNetの江島氏のBLOGに詳しい
• http://blog.japan.cnet.com/kenn/archives/003149.html
– サーバからクライアントへの通信をリアルタイムに行って、情報を擬似的にプッシュを
実現する
– KeepAllive=trueでつなぎっぱなしの仕組み
• スレッドが爆裂する問題にどう取り組むか?その答えがNBソケット
•
GrizzlyではComet対応が標準組み込み
1)と6)の間には長い時間経過を許
す。2)による書き込みがなければ、
ずっとつなぎっぱなしで待機。
http://www.machu.jp/diary/20060411.html より図を引用
© 2006 The Seasar Foundation and the Others, All rights reserved.
まとめ
• Grizzlyはプロトコルハンドラをつくるためのフ
レームワークである
• 特別踏み込まなければ驚くほど簡単
• NIOのNBソケットをゼロから使って同様なも
のを作ってもいい、しかしいろいろ嵌るので
Grizzlyを使うと吉
• 基本的なNBソケットによるHTTPハンドラに
加え、SSL対応、非同期処理、Cometエンジ
ンがそれぞれ標準で組み込まれている
© 2006 The Seasar Foundation and the Others, All rights reserved.
今回触れなかったもの その1
• 今回触れなかった、2つのパッケージ
– com.sun.enterprise.web.ara
– com.sun.enterprise.web.portunif
• ARA
– Grizzly’s Application Resources Allocation
– RCMの実装、JSR284にて作業中のものを意識
• Resource Consumption Management
• Googleのリードで、2006年12月18日にパブリックレ
ビュー終了したところ。これからファイナルドラフトへ
• あらゆるJavaアプリケーションで扱う「リソース」を管理
する仕組み。Grizzlyではスレッドとメモリに注目。
– ルールベースによるReadタスクの分散技術?
© 2006 The Seasar Foundation and the Others, All rights reserved.
今回触れなかったもの その2
• 今回触れなかった、2つのパッケージ
– com.sun.enterprise.web.ara
– com.sun.enterprise.web.portunif
• PortUnif
– TCPソケットの送信バイトをちょっと見て、プロトコルの種
類を識別する仕組み?単一ポートで複数プロトコルを取り
扱うことが狙いのようである。HTTPとHTTPSを扱うもの
が同梱されている
SelectorThread st = new SelectorThread();
st.setPipelineClassName(PortUnificationPipeline.class.getName());
…
st.initPipeline();
PortUnificationPipeline pup = (PortUnificationPipeline)st.getReadPipeline();
pup.addProtocolFinder(…);
pup.addProtocolHandler(…);
© 2006 The Seasar Foundation and the Others, All rights reserved.
今回説明できなかったこと
• SSLを利用したGrizzlyアプリケーション
– 時間作って、GlassFishのコードを読んでみます
• ARP、Cometの具体的動き
– これは理解&ちゃんと動作済み。しかし当面取り
組むネタが無い。可能性を考察していきましょう。
– 整理:
• ビジネスロジックを実行するのに、時間がかかるとき
有効な仕組み
• NBソケットは基本的にシングルスレッドの下で動くの
で、これをちゃんとやらないと全体速度に関わる
• Cometは今、ホットな話題だそうです。手軽には
CometdやJetty6で試すことができます。
© 2006 The Seasar Foundation and the Others, All rights reserved.
Grizzlyに無いもの
• WEBコンテナを作る上でGrizzlyに無いもの
– そもそも:WEBコンテナ仕様
– ブートストラップ
– アプリケーションコンテナ
• 仮想化されたファイルシステム
– セッションマネジメント
• クラスタリング
– 認証関連
• Grizzlyにあるけど作りたくなるもの
– リクエストパーサ、レスポンスアウトプッター
– ログ出力
– JMX対応等、管理関連 (JMX、あるのです!)
© 2006 The Seasar Foundation and the Others, All rights reserved.
参考資料
• 開発者:Jean-Francois ArcandのBlog
– http://weblogs.java.net/blog/jfarcand/
– GrizzlyおよびNIOの高度な話題、しかし更新頻度が低い。
• JavaOne2005/2006プレゼンテーション
– http://72.5.124.65/learning/javaoneonline/2005/webtie
r/TS-3227.pdf
– http://weblogs.java.net/blog/jfarcand/archive/2006_B
OF0520.pdf
• Grizzlyソース
– ほか、AsyncWebやJettyソースのごく一部
• NIOによるNon-Blockingソケット通信
– 「ServerSocketChannel」「Selector」「SelectionKey」な
どで検索すると結構たくさん出てくる。しかし、ほぼ初級な
話題。
© 2006 The Seasar Foundation and the Others, All rights reserved.
おまけ
© 2006 The Seasar Foundation and the Others, All rights reserved.
フレームワークの限界
• 最近の私の主張
– いろいろありますが、アプリケーションに近いF/Wだけで
なんとかできることも減ってきてるでしょ?(以下略)
– バカ対策F/Wを否定するのであれば、その解決策を模索
していかなければならない
• 私の考える二つの方向性へのヒント
– WEBコンテナなど、アプリケーションのブートストラップか
らの見直し -> Grizzlyの出番もあるか?Kvasir?
– EclipseプラグインなどのIDEだけに止まらない、開発環
境アプリケーションの創造
• しばらく具体的な話は蒸発する状態でのみします
– ほら、世間って怖いしw。。。ということで今日、放談。
– 具体的なアプリケーションを見せないと、机上の空論だし
© 2006 The Seasar Foundation and the Others, All rights reserved.