【问题标题】:Clustered Vert.x not working in docker if vert.x instance is created manually如果手动创建 vert.x 实例,则集群 Vert.x 无法在 docker 中工作
【发布时间】:2018-08-11 14:30:47
【问题描述】:

我设置了一个小项目来在集群环境中学习 Vert.x 的功能,但是当我尝试在 Docker 映像中创建 vertx 实例时遇到了一些奇怪的问题。

该项目仅包含 2 个部署在不同 Docker 容器中并使用事件总线相互通信的 Verticle

如果我使用 vertx 提供的启动器:

    Launcher.executeCommand("run", verticleClass, "--cluster")

(或者只是说明主类是io.vertx.core.Launcher 并输入正确的参数)

一切都在本地和 docker 镜像中运行。但是如果我尝试手动创建 vertx 实例

Vertx.rxClusteredVertx(VertxOptions())
        .flatMap { it.rxDeployVerticle(verticleClass) }
        .subscribe()

然后它在 Docker 中不起作用(它在本地工作)。或者,更直观

| |本地 |码头工人 | |:---------------: |:-----: |:------: | | Vertx 启动器 |是 |是 | |自定义启动器 |是 | N |

通过检查 Docker 日志,似乎一切正常。我可以看到两个verticles互相认识:

Members [2] {
    Member [172.18.0.2]:5701 - c5e9636d-b3cd-4e24-a8ce-e881218bf3ce
    Member [172.18.0.3]:5701 - a09ce83d-e0b3-48eb-aad7-fbd818c389bc this
}

但是当我尝试通过事件总线发送消息时,会抛出以下异常:

WARNING: Connecting to server localhost:33845 failed
io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/127.0.0.1:33845
    at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
    at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
    at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:325)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:340)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:633)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.ConnectException: Connection refused
    ... 11 more

只是为了简化我上传的项目to Github。我试图让它尽可能简单,所以它有 2 个 Verticle 和 2 个主类以及每个组合的大量脚本

【问题讨论】:

    标签: docker vert.x


    【解决方案1】:

    通过检查 Docker 日志,似乎一切正常。我可以看到 两个verticles互相认识

    是的,因为您的集群管理器工作正常,但您还应该使您的事件总线配置在集群中的每个节点(机器/docker 容器)中保持一致,因为如 Vert.x 文档中所述:集群管理器不处理事件总线节点间传输,这由 Vert.x 通过 TCP 连接直接完成。

    您必须将每个节点上的集群主机设置为该节点本身的 IP 地址和任意端口号(除非您尝试在同一节点上运行多个 Vert.x 实例,否则您必须为每个节点选择不同的端口号Vert.x 实例)。您面临的错误是因为默认集群主机是 local host

    例如,如果一个节点的 IP 地址是 192.168.1.12,那么您将执行以下操作:

    VertxOptions options = new VertxOptions()
                    .setClustered(true)
                    .setClusterHost("192.168.1.12") // node ip
                    .setClusterPort(17001) // any arbitrary port but make sure no other Vert.x instances using same port on the same node
                    .setClusterManager(clusterManager);
    

    在另一个 IP 地址为 192.168.1.56 的节点上,您将执行以下操作:

    VertxOptions options = new VertxOptions()
                    .setClustered(true)
                    .setClusterHost("192.168.1.56") // other node ip
                    .setClusterPort(17001) // it is ok because this is a different node
                    .setClusterManager(clusterManager);
    

    【讨论】:

    • 如果集群 IP 在编译时已知,这将起作用,但事实并非如此。我研究了 vertx Launcher 如何在添加为响应时做到这一点
    【解决方案2】:

    通过对 Vert.X Launcher 代码的更多研究,我发现它在内部做的事情不仅仅是“解析”输入

    如果 vertx 配置为在集群模式下运行,Launcher 正在设置集群地址本身(通过 BareCommand 类),因此为了使用您自己的 Main 类复制 Launcher 行为(并且具有通过代码而不是通过 args 灵活配置您的 vertx 实例)代码如下:

    fun main(args: Array<String>) {
    
        Vertx.rxClusteredVertx(
                VertxOptions(
                        clusterHost = getDefaultAddress()
                )
        )
                .flatMap { it.rxDeployVerticle(verticleClass) }
                .subscribe()
    }
    
    
    // As taken from io.vertx.core.impl.launcher.commands.BareCommand
    fun getDefaultAddress(): String? {
        val nets: Enumeration<NetworkInterface>
        try {
            nets = NetworkInterface.getNetworkInterfaces()
        } catch (e: SocketException) {
            return null
        }
    
        var netinf: NetworkInterface
        while (nets.hasMoreElements()) {
            netinf = nets.nextElement()
    
            val addresses = netinf.inetAddresses
    
            while (addresses.hasMoreElements()) {
                val address = addresses.nextElement()
                if (!address.isAnyLocalAddress && !address.isMulticastAddress
                        && address !is Inet6Address) {
                    return address.hostAddress
                }
            }
        }
        return null
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-03
      • 2021-06-29
      • 2020-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      相关资源
      最近更新 更多