Vert.x高可用性无效

问题描述 投票:2回答:1

Brief description

我刚刚开始使用VertX,我想通过一个小玩具示例来尝试高可用性功能。在我的设置中,我有一个胖的应用程序,它被部署到几个docker容器中。应用程序以编程方式创建VertX实例并启动一个名为ContainerVerticle的Verticle。这将运行HTTP服务器并充当“启动器” - 当收到“SPAWN”命令时,它会在高可用性模式下部署另一个名为AppVerticle的Verticle。我的想法是,我希望在3个容器上运行它,然后在其中一个容器上杀死JVM,这应该将AppVerticle重新部署到另一个docker容器。

实际结果:Verticle可以使用事件总线相互通信,集群似乎也能正常工作:根据日志文件,成员可以看到对方。但是,当我杀死一个Verticle时,它没有被重新部署。

More details

(所有源代码都是用Kotlin编写的)Vertx初始化:

    val hzConfig = Config()
    val mgr = HazelcastClusterManager(hzConfig)  // empty config -> use default
    val hostAddress = getAddress() // get the local ip address (not localhost!)

    val options = VertxOptions()
            .setClustered(true)
            .setClusterHost(hostAddress)
            .setClusterPort(18001)
            .setClusterManager(mgr)
            //.setQuorumSize(2)
            .setHAEnabled(true)

    val eventBusOptions = EventBusOptions()
    eventBusOptions
            .setClustered(true)
            .setHost(hostAddress)
            .setPort(18002)
    options.setEventBusOptions(eventBusOptions)

    Vertx.clusteredVertx(options) { res ->
        if (res.succeeded()) {
            val vertx = res.result()
            vertx.deployVerticle(ContainerVerticle::class.java.name,
                    DeploymentOptions()
                            .setHa(false)) // ContainerVerticle should not restart
        }
    }

ContainerVerticle(我们的'发射器')

class ContainerVerticle : AbstractVerticle() {
    ...
    override fun start(startFuture: Future<Void>?) {

        val router = createRouter()
        val port = config().getInteger("http.port", 8080)

        vertx.eventBus().consumer<Any>("mynamspace.container.spawn") { message ->
            val appVerticleID = message.body()
            log.info(" - HANDLE SPAWN message \"${appVerticleID}\"")
            val appVerticleConfig = JsonObject().put("ID", appVerticleID)

            vertx.deployVerticle(AppVerticle::class.java.name, // Deploy the APP!!!
                    DeploymentOptions()
                            .setConfig(appVerticleConfig)
                            .setInstances(1)
                            .setHa(true))
        }

        vertx.createHttpServer()...  // omitted (see github link)
    }

    private fun createRouter(): Router { ... } // omitted (see github link)

    val handlerRoot = Handler<RoutingContext> { routingContext ->
        val cmd = routingContext.bodyAsString
        val tokens = cmd.split(" ")
        if (tokens[0] == "spawn") {
            vertx.eventBus().send("mynamspace.container.spawn", tokens[1])  // round-robin
            routingContext.response().end("Successfully handled command ${cmd}\n")
        } else if (tokens[0] == "send") {
            vertx.eventBus().send("mynamspace.app.${tokens[1]}", tokens[2])
            routingContext.response().end("success\n")
        } else {
            routingContext.response().end("ERROR: Unknown command ${cmd}\n")
        }
    }
}

最后一部分:AppVerticle:

class AppVerticle : AbstractVerticle() {
    var timerID = 0L
    override fun start(startFuture: Future<Void>?) {
        val id = config().getString("ID")
        log.info(" SPAWNED app verticle \"${id}\"")

        vertx.eventBus().consumer<Any>("mynamspace.app.${id}") { message ->
            val cmd = message.body()
            log.info(" - app verticle \"${id}\" handled message ${cmd}")
        }

        timerID = vertx.setPeriodic(1000) {
            log.info(" - app verticle \"${id}\" is alive")
        }
    }
}

Running

打开3个终端并运行3个泊坞窗实例。次要细节:这里我们将端口8080重新映射到三个不同的端口8081,8082,8083,我们还为容器提供了唯一的名称:cont1,cont2,cont3

docker run --name "cont1" -it --rm -p 8081:8080 -v $PWD/build/libs:/app anapsix/alpine-java java -jar /app/vertxhaeval-1.0-SNAPSHOT-all.jar

docker run --name "cont2" -it --rm -p 8082:8080 -v $PWD/build/libs:/app anapsix/alpine-java java -jar /app/vertxhaeval-1.0-SNAPSHOT-all.jar

docker run --name "cont2" -it --rm -p 8083:8080 -v $PWD/build/libs:/app anapsix/alpine-java java -jar /app/vertxhaeval-1.0-SNAPSHOT-all.jar

Observation 1

由于以下消息,集群成员似乎看到了彼此:

Members [3] {
    Member [172.17.0.2]:5701 - 1d50394c-cf11-4bd7-877e-7e06e2959940 this
    Member [172.17.0.3]:5701 - 3fa2cff4-ba9e-431b-9c4e-7b1fd8de9437
    Member [172.17.0.4]:5701 - b9a3114a-7c15-4992-b609-63c0f22ed388
}

我们也可以跨越AppContainer

curl -d "spawn -={Application-1}=-" -XPOST http://localhost:8083

消息总线似乎正常工作,因为我们看到生成的消息以循环方式传递给ContainerVerticle

Observation 2- the problem

现在让我们尝试杀死垂直(假设它在cont2中运行):

docker kill --signal=SIGKILL  cont2

其余容器似乎对该事件做出反应,日志文件具有如下内容:

Aug 14, 2018 8:18:45 AM com.hazelcast.internal.cluster.ClusterService
INFO: [172.17.0.4]:5701 [dev] [3.8.2] Removing Member [172.17.0.2]:5701 - fbe67a02-80a3-4207-aa10-110fc09e0607
Aug 14, 2018 8:18:45 AM com.hazelcast.internal.cluster.ClusterService
INFO: [172.17.0.4]:5701 [dev] [3.8.2] 

Members [2] {
    Member [172.17.0.3]:5701 - 8b93a822-aa7f-460d-aa3e-568e0d85067c
    Member [172.17.0.4]:5701 - b0ecea8e-59f1-440c-82ca-45a086842004 this
}

然而,AppVerticle没有重新部署。

完整的源代码可以在github:https://github.com/conceptacid/vertx-ha-eval上找到

docker hazelcast vert.x high-availability
1个回答
4
投票

我花了几个小时调试这个,但终于找到了它。

所以这是解决方案:

您的Verticle start方法标题是:

override fun start(startFuture: Future<Void>?)

你正在覆盖启动方法,这些方法为你提供了在Verticle开始之后等待的未来。由于你不打电话,Vert.x会永远等待这个未来的完成

startFuture.complete()

在方法的最后。

因此,Verticle永远不会被添加到HAManager的verticle-list中,因此不会被重新部署。

或者,您可以使用

override fun start()

如果您的Verticle进行简单的同步启动,则作为方法标题。

希望这可以帮助。

© www.soinside.com 2019 - 2024. All rights reserved.