GroovyでVert.x

G* Advent Calendarの10日目です。

G*ネタ、とは言いがたいですが、他の方とネタがなるべく被らず、斜め下を行くよう、ロンドンで行われたGroovy & Grails eXchange 2011の初日のセッション、Peter Ledbrookさんの「Asynchronous IO on the JVM」からVert.xをご紹介したいと思います。

Vert.xとは?

「Vert.xってなに?」ということですが、READMEによると、

The next generation polyglot asynchronous application framework. (Formerly known as node.x)
次世代の多言語非同期アプリケーションフレームワーク。(以前はnode.xとして知られていた)

だそうです。特徴としては、

  • JVM上で動く。
  • Node.jsのようなイベント駆動型フレームワークのよいところを取り入れる。
  • すべてノンブロッキング
  • 多言語に対応。vert.xは、Ruby、Groovy、JavaJavaScriptPythonClojureScalaといった複数の言語から利用できるようになる予定。現在、JavaRubyをサポート。
  • Java7のInvokeDynamicを使って開発を進め、動的言語にとって有望な実行環境であるJVMに賭けている。
  • ネットワークサーバーやクライアントが簡単に作成できる。
  • 真のスケーラビリティ。他のよく知られているイベント駆動型フレームワークとは異なり、プロセスごとに複数のイベントループを持つことができる。
  • 非常にシンプルな並行性モデル。シングルスレッドでコードを書くと、複数のコア間でスケールするのがわかる。競合状態やロックを心配する必要はない。
  • TCPSSL、HTTP、HTTPS、Websocketsといった従来のプロトコルにとどまらず、複数のネットワークプロトコルを解釈する。
  • ユーザー空間をバイパスしてファイルシステムから静的ファイルを効率的に提供。
  • Sinatra/Expressスタイルの単純なリソース・ルーティング。
  • 分散イベントバス。分散イベントバスの提供のため、複数vert.xインスタンスがシームレスに連携。

だそうです。

Vert.xアーキテクチャ

Vert.xのコア部分はJavaで書かれており、サポート言語ごとにAPIが用意されています(現状はJavaRubyだけのようですが)。
内部的には、NettyとNIO 2が使われています。
また、Reactorパターンに基づいて実装されているようです。

動かしてみる

Vert.xを動かしてみます。動作するOSとしては、LinuxOSXJDKは7以上が必要なようです。
今回は、次の環境で動かしてみます。

Vert.xのビルド

Binary Releaseがあるのですが、Groovy用のソースが反映されていない気がするので、ソースを取得しビルドします。

ビルドの手順はここを参考にします。

githubからソースを取得します。今回は、Peter LedbrookさんとこからGroovy SupportのZIPで取得します。

次のアプリをインストールして、環境変数PATHに設定します。

  • Apache ant 1.8.2
  • JDK 1.7.0_01
  • JRuby 1.6.5
  • Yard ('jruby -S gem install yard'でインストール)
  • Groovy 1.8.4

取得したZIPを展開したソースディレクトリのルートで、antを実行し、配布・実行用のファイルを作成します。

$ ant dist

実行後、ソースディレクトリのルート/targetディレクトリに、vert.x-0.1.tar.gzができます。

Vert.xのインストール

先程作成したvert.x-0.1.tar.gzを展開し、展開して作成されるbinディレクトリを環境変数PATHに設定します。

$ tar zxvf vert.x-0.1.tar.gz

今後、展開したディレクトリをVERTX_HOMEとして話を進めます。

Vert.xのライフサイクル

Vert.xの起動から停止までのライフサイクルは、次のようです。

  1. Vert.xインスタンスの起動
  2. アプリケーションのデプロイ
  3. クライアントからアクセス
  4. アプリケーションのアンデプロイ
  5. Vert.xインスタンスの停止

Vert.xインスタンスの起動

Vert.xのインスタンスを起動します。

$ vertx start
vert.x server started

デフォルトで、ポート25571でリクエストをリッスンします。-portで、ポート番号を変更できます。

$ vertx start -p 35571
vert.x server started

また、-clusterで、クラスターモードで起動するようです。

$ vertx start -cluster
vert.x server started in clustered mode

アプリケーションのデプロイ

サーバアプリケーションをデプロイします。サーバアプリケーションは、org.vertx.java.core.app.VertxAppをクラスとなります。
展開したソースの中にGroovyで書かれたEchoサーバのサンプルソース(EchoServer.groovy)がありますので、今回はそれを動かしてみます。

$ cd $VERTX_HOME/examples/groovy
$ vertx deploy -groovy -name EchoServer -main echo/EchoServer.groovy -cp . -instances 1
Deploying application name: EchoServer instances: 1
OK
  • -groovyで、Groovyのアプリケーション(ソースファイル)をデプロイすることを指定します。
  • -nameで、アプリケーション名を指定します。
  • -mainで、アプリケーションのクラス、またはスクリプトファイル名を指定します。
  • -cpで、クラスパスを指定します。
  • -instancesで、アプリケーションのインスタンス番号を指定します。

Vert.x側では、次のログが出力されます。

[vert.x-core-thread-0] 18:17:03,339 INFO [org.vertx.java.core.app.AppManager]  Deploying application name : EchoServer type: GROOVY main class: echo/EchoServer.groovy instances: 1
[vert.x-core-thread-0] 18:17:04,305 INFO [org.vertx.java.core.app.AppManager]  Started 1 instances ok

クライアントからアクセス

サーバにアクセスしてみます。
展開したソースの中にGroovyで書かれたEchoクライアントのサンプルソース(echoclient.groovy)がありますので、サーバと同様、それを動かしてみます。

$ groovy -cp ../../lib/java/vert.x.jar:../../lib/java/netty.jar echoclient.groovy 
Press Ctrl-C to exit
Net client sending: hello 0
Net client sending: hello 1
Net client sending: hello 2
Net client sending: hello 3
Net client sending: hello 4
Net client sending: hello 5
Net client sending: hello 6
Net client sending: hello 7
Net client sending: hello 8
Net client sending: hello 9
Net client receiving: hello 3

Net client receiving: hello 2

Net client receiving: hello 5

Net client receiving: hello 1

Net client receiving: hello 7

Net client receiving: hello 8

Net client receiving: hello 0

Net client receiving: hello 4

Net client receiving: hello 6

Net client receiving: hello 9

アプリケーションのアンデプロイ

必要に応じて、アプリケーションをアンデプロイします。

$ vertx undeploy -name EchoServer
OK

アンデプロイするアプリケーション名を指定します。

Vert.x側では、次のログが出力されます。

[vert.x-core-thread-0] 18:30:47,893 INFO [org.vertx.java.core.app.AppManager]  Undeploying 1 instances of application: EchoServer
[vert.x-core-thread-0] 18:30:47,902 INFO [org.vertx.java.core.app.AppManager]  Undeployed ok

Vert.xインスタンスの停止

フォアグラウンドで実行している場合、Ctrl-Cで停止することができますが、バックグラウンドで実行している場合、stopでVert.xのインスタンスを停止します。

$ vertx stop
Stopped vert.x server

別のサンプルを実行してみる - その1

次に、別のサンプルを試してみます。Redisを使用した、ヒット数を記録しそれを返すサンプルアプリケーションです。このサンプルを実行するには、Redisサーバが起動されている必要があります。
アプリケーションをデプロイします。

$ cd $VERTX_HOME/examples/groovy
$ vertx deploy -groovy -name RedisServer -main redis/RedisExample.groovy -cp .
Deploying application name: RedisServer instances: -1
OK

クライアントを実行します。

$ groovy -cp ../../lib/java/vert.x.jar:../../lib/java/netty.jar redisclient.groovy 
Final output: <html><body><h1>Hit count is 5001</h1></body></html>
$ groovy -cp ../../lib/java/vert.x.jar:../../lib/java/netty.jar redisclient.groovy 
Final output: <html><body><h1>Hit count is 10002</h1></body></html>
$ groovy -cp ../../lib/java/vert.x.jar:../../lib/java/netty.jar redisclient.groovy 
Final output: <html><body><h1>Hit count is 15003</h1></body></html>
$ groovy -cp ../../lib/java/vert.x.jar:../../lib/java/netty.jar redisclient.groovy 
Final output: <html><body><h1>Hit count is 20004</h1></body></html>

クライアントの実行ごとに、Hit countが増加するのがわかります。

別のサンプルを実行してみる - その2

最後に、また別のサンプルを試してみます。WebSocketsを使用したサンプルアプリケーションです。
サンプルアプリケーションがあるディレクトリでVert.xを起動します。

$ cd $VERTX_HOME/examples/groovy
$ vertx start
vert.x server started

アプリケーションをデプロイします。

$ cd $VERTX_HOME/examples/groovy
$ vertx deploy -groovy -name WebSockets -main websockets/WebSocketsExample.groovy -cp .
Deploying application name: WebSockets instances: -1
OK

Chromehttp://localhost:8080/にアクセスします。

テキストボックスだけのページが表示されます。
テキストボックスに何か入力すると、入力した文字がどんどん追加されていくのがわかると思います。
#日本語は何故かダメみたいです...orz

まとめ

Vert.xをGroovyで動かすソースは、Peter Ledbrookさんとこのブランチだけのようですが、出来れば、本家に早めに取り込まれて欲しいものです。
サンプルのソースなど追わず、今回は紹介ベースなので、時間があればアプリケーションをどのように書くものなのか、などなど、いろいろと調べてみたいと思います。

さ〜て、次回のG* Advent Calendarさんは?

G* Advent Calendarの11日目は、帰国直前?直後?の[twitter:@bikisuke]さんです。