LoginSignup
15
16

More than 5 years have passed since last update.

VertxでVerticleを起動させるメモ

Posted at

はじめに

最近は関数型言語が流行りつつあるので、僕も乗り遅れまいと(すでに乗り遅れている感じが否めないが)Vertxを学んでみる。
ちなみにVertxとは何か・・・というと僕は正確な答えを持ってない。
僕のイメージでは負荷分散プログラムのフレームワークというイメージ。

とりあえず、僕のイメージでVertxを語ってみる。(間違ってるかもしれないので、鵜呑みにしないように!w)

Vertxって?

プログラムの最小単位をVerticleと定めて、Verticle単位でプログラムを動かす事を目的としている。
例えばServerVerticleというHTTPリクエストを待ち受けるプログラムを書いたとした場合に、リクエストを受けるのはServerVerticleだが実際の処理はUserVerticleに任せる場合は以下のようになる。

HTTPリクエスト → ServerVerticle → UserVerticle → HTTPレスポンス

これだけだと何が良いのかわからないと思う。

Vertxの特徴はVerticle単位でプログラムが動くため、ServerVerticleとUserVerticleは別々のメモリ空間で動作している。
そのVerticle間のやりとりはメッセージで行うことによって疎結合を実現しているのだ。
なので、プログラム単位に割くメモリを割り当てる事ができて負荷が重いプログラムにはメモリを多く割り当てるなどを動的に行えるのだ!

動的にメモリを割り当てる(正確にはVerticle数を増やしたり減らしたりできる)というのは、あるプログラムの負荷が上がった際に局部的にメモリを増やせるということだ。
通常のアプリケーションの場合は、サーバー台数を増やしたりしなければならないところをプログラム単位で増強できればコスト削減にも繋がるし高負荷時の対応も即時に行える。

プログラムが自動的にVerticleの数を制御してくれれば突然高負荷になっても何も対応しないで済むかもしれないのだ!
・・・と書いてますが、僕は実際に検証したわけではありません。(汗

Verticleって?

VerticleはVertx上のでプログラム最小単位です。(最大単位と書いても合ってる気がする・・・。)
上記にも記載した通りで、VertxはVerticle単位でメモリ空間を確保してます。
なので、Verticle同士の干渉はメッセージのやり取りだけで行います。

ということは・・・状態をサーバー側で持てない事を示してます。
すなわち副作用のない関数を書く必要があります。
(Vertxではサーバーを跨いでデータを扱えるSyncMapがあります。また、DBへのアクセスなどもあるのでこの表現は間違ってますが説明上このように書いてます。)

「副作用がない・状態を保持しない」プログラムと言うと、オブジェクト指向をずっと使ってた人には若干とっつきにくそうです。
というか、僕はとっつきにくかったです。
しかし、この概念があるためVertxは以下の恩恵があります。

  • Verticle単位でプログラムの数を変更できる。
  • メインループが専有されて他のプログラムに影響することがない。(重い処理をVerticleに記載してはいけない。)
  • Verticle内のプログラム言語を自由に選べる。(インターフェースが決まっているため)

これは、素早いレスポンスを要求されるWebSocketなどで大きな威力を発揮します。

Vertxのインストール

とりあえず、イメージをつかむために動かしてみましょう!
まずはJava8をインストールしてください。
僕は1.8.0_31をインストールします。
また、以下の説明はMacで行いますが特にプラットフォームには依存しないのでWindowsでも動きます。

Vertx3をインストールする。

vertxのホームページより本体をダウンロードしてください。
僕はここからvert.x-3.0.0-full.zipをダウンロードして解凍しました。
※パスを通すため全角文字や空白が含まれていないフォルダに解凍すると余計な障害に見舞われません。

Pathを通します。

僕は.bash_profileに以下のように記載しました。

PATH="$PATH":[解凍フォルダのパス]/vert.x-3.0.0/bin

パスを読み込みます。(Windows用にvertx.batも用意されてました。未確認ですが、多分Windowsでも動きます。)

$> source .bash_profile

インストールの確認をします。

$> vertx
Listening for transport dt_socket at address: 8000
....

と表示されればvertxの設定は完了です。

動かしてみる。

設定が終わったら動かしてみましょう。

Java編

以下のファイルを適当なフォルダに作成してください。

JavaVerticle.java
import org.vertx.java.core.Handler;
import org.vertx.java.core.http.HttpServerRequest;
import org.vertx.java.platform.Verticle;

public class JavaVerticle extends Verticle {

  public void start() {
    vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
      public void handle(HttpServerRequest req) {
        req.response().headers().set("Content-Type", "text/plain");
        req.response().end("Hello Java!");
      }
    }).listen(8080);
  }
}

同フォルダでvertxを起動します。

$> vertx run JavaVerticle.java
Listening for transport dt_socket at address: 8000
Succeeded in deploying verticle

と表示されればOKです。
localhost:8080をブラウザで見てもらえるとHello Java!と表示されているはずです。

Groovy編

Javaと同様にGroovyでも動かしてみましょう。
Groovyを動かすために何か必要なものはありません。

GroovyVerticle.groovy
import org.vertx.groovy.platform.Verticle

class GroovyVerticle extends Verticle {
    @Override
    def start() {
        vertx.createHttpServer().requestHandler { request ->
            request.response.putHeader("Content-Type", "text/plain")
            request.response.end("Hello Groovy!")
        }.listen(8070)
    }
}

動かしてみましょう。

$> vertx run groovy:GroovyVerticle
Listening for transport dt_socket at address: 8000
Succeeded in deploying verticle 

Groovyの起動ではgroovy:が必要です。代わりにファイル拡張子は不要です。指定すると落ちます。
localhost:8070をブラウザで見てもらえるとHello Groovy!と表示されているはずです。

両方同時に動かしてみましょう

先ほどVerticleは自由に増やしたりできると書きました。
実際に複数のVerticleを起動してみましょう。

App.groovy
container.deployVerticle('groovy:GroovyVerticle')
container.deployVerticle('JavaVerticle.java')

こちらのファイルを作成します。

$> vertx run App.groovy 
Listening for transport dt_socket at address: 8000
Succeeded in deploying verticle 

上記のファイルを実行するとVerticleが二つ起動されます。
試しにlocalhost:8080localhost:8070へアクセスしてみてください。
両方のVerticleが動作していることを確認できると思います。
※なぜかここはgroovy:を書かなくても動く。Verticleを起動するときだけ必要なのかもしれない。(汗

App.groovy
container.deployVerticle('groovy:GroovyVerticle', 10)
container.deployVerticle('JavaVerticle.java', 15)

上記のように設定するとGroovyVerticleを10個、JavaVerticleを15個起動させることができます。
(多分w。確認はしてませんが、動きました・・・。)

また、外部からverticleの数を変えることも出来ますが・・・やり方をメモったファイルを紛失してしまったので本記事では割愛します。(汗

最後に説明

とりあえず、Verticleの起動方法は分かったかと思います。
コードを見ていただければ分かると思いますが、Verticleが起動するとstartメソッドがまず呼び出されます。
ここでVerticleの初期処理を行います。

上記の例ではHTTPの待ち受けを行ってますが、他では以下のことを行ったりします。

  • WebSocketの待ち受け
  • イベントハンドラ(vertx.eventBus)の登録

・・・って、書いておきながら僕は上記の2点くらいしかしたことがなかったです。はい。
長くなってきたのでVerticle同士のメッセージやりとりをするイベントハンドラについては別記事で記載します。
また、その際にSyncMapについても書こうと思います。

ReactiveがVertx3で使えるようになったので、こちらについても調べたいのですが・・・ここまで調べれるかどうかは疑問です・・・。
(というのも、Vertxは業務で使用しているわけではないので・・・)

おまけ

本当はWebSocketの通信方法を書きたかったのですが、検証が面倒なのでここでの題材にあげませんでした。

が!
興味のある方もいると思いますので、Groovyのコードだけ貼り付けておきます。
※Vertx2で動かしていたコードです。説明はしませんw

WsServerVerticle.groovy
import org.vertx.groovy.core.buffer.Buffer
import org.vertx.groovy.core.eventbus.Message
import org.vertx.groovy.core.http.ServerWebSocket
import org.vertx.groovy.platform.Verticle
import org.vertx.java.core.impl.VertxInternal

import org.vertx.java.core.json.JsonArray
import org.vertx.java.core.spi.cluster.ClusterManager

class WsServerVerticle extends Verticle {
    @Override
    def start() {
        // スタックオーバーフローでは下記のように取得していた。
        // http://stackoverflow.com/questions/12299132/clustering-and-shared-data-in-vert-x
        // ClusterManager clusterManager = ((VertxInternal)vertx).clusterManager()
        // Map map = clusterManager.getSyncMap("mapName");
        // 実際は以下のように取ってた。(以下のコードはこのサンプルでは使ってません。)
        ClusterManager clusterManager = ((VertxInternal)vertx.toJavaVertx()).clusterManager()
        Map map = clusterManager.getSyncMap("mapName");

        // WebSocketを起動
        vertx.createHttpServer().websocketHandler {ServerWebSocket ws ->
            onOpen(ws)
        }.listen([ポート番号], [アドレス(0.0.0.0)])
    }

    @Override
    def stop() {
    }

    // WebSocketのコネクションが開かれた場合の処理
    private def onOpen(ServerWebSocket ws) {
        println "open"
        // クライアントへ書き込む関数
        def writeHandler = { Message message ->
            // wsインスタンスをキャプチャーしてる。(上の説明で状態を持たないって書いてたが、こういう場合もある。)
            ws?.writeBinaryFrame(new Buffer((byte[])message.body))
        }

        // 他のVerticleからもクラアントへ書き込めるようにする。
        vertx.eventBus.registerHandler([クライアント毎に識別した名称("WS_ID_"+userIdみたいな感じ)], writeHandler)

        // WebScoketへ通知があった場合の処理
        ws.dataHandler { data ->
            onMessage(data)
        }

        // WebSocket切断処理
        ws.closeHandler {
            // 作成したイベントバスを削除しておく。
            vertx.eventBus.unregisterHandler([クライアント毎に識別した名称("WS_ID_"+userIdみたいな感じ)], writeHandler)
            println "close"
        }
    }

    // WebSocketのデータ受信ハンドラの定義
    private def onMessage(Buffer data) {
        // 受け取ったメッセージの処理を行う。

        // 実際の処理を行うVerticleを呼び出す。
        vertx.eventBus.send([他のVerticleで登録したイベントバスを呼び出す。], data) { Message msg ->
            // 結果をクライアントへ通知する
            vertx.eventBus.send([クライアント毎に識別した名称("WS_ID_"+userIdみたいな感じ)], (JsonArray)msg.body)
        }
    }
}

参考にしたサイト

Vert.x がいいね!

Vertx2のメモ

僕用のメモです。
Vertx2で使ってた設定をメモに残しておきます。

読者の方は読み飛ばしてください。

デバッグ

Vertx3では未確認ですが、Vertx2では以下の設定を[解凍フォルダのパス]/vert.x-3.0.0/bin/vertxに記載しました。

JVM_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"

mod.jsonはどこに・・・?

Vertx3でも同じ構成なのだろうか??

Vertx2では以下の場所に配置されていたが・・・。
https://github.com/vert-x/vertx-gradle-template/tree/master/src/main/resources

Vertx3ではなくなってる・・・。
ってか、別にテンプレートがあるのか???
https://github.com/vert-x3/vertx-examples/tree/master/gradle-simplest

Gradleの設定が大きく変わってないか??

Vertx2
https://github.com/vert-x/vertx-gradle-template/blob/master/build.gradle

Vertx3
https://github.com/vert-x3/vertx-examples/blob/master/gradle-simplest/build.gradle

僕はGradleに明るくないけど、Vertx3ではMain-Classで初期処理をするVerticleを指定できるようになったのかな?
Vertx2では以下のコマンドで起動してた。

$> CLASSPATH=[先に読み込みたいライブラリ]/lib/*:. vertx run [起動したいVerticle] -cluster -cp build/classes/main -conf [読み込みたいConfig]

[VERTX_HOME]/conf/langs.propertiesもなくなってる・・・。

15
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
16