如何配置Vert.x事件总线以跨Docker容器群集工作?

问题描述 投票:5回答:3

在我目前的设置中,我使用的是Hazelcast集群管理器的默认多播选项。当我链接我的容器化Vertx模块的实例(通过Docker网络链接)时,我可以看到他们成功创建了Hazelcast集群。但是,当我尝试从一个模块在事件总线上发布事件时,另一个模块不会对它做出反应。我不确定Hazelcast群集中的网络设置如何与事件总线的网络设置相关。

目前,我为每个Vert.x模块配置了以下编程配置,每个模块都部署在一个docker容器中。

ClusterManager clusterManager = new HazelcastClusterManager();
VertxOptions vertxOptions = new VertxOptions()
            .setClustered(true)
            .setClusterManager(clusterManager);
vertxOptions.setEventBusOptions(new EventBusOptions()
            .setClustered(true)
            .setClusterPublicHost("application"));

Vert.x Core手册指出我可能必须为事件总线配置clusterPublicHostclusterPublicPort,但我不确定它们与一般网络拓扑有何关联。

java docker hazelcast vert.x event-bus
3个回答
8
投票

答案就在这里https://groups.google.com/d/msg/vertx/_2MzDDowMBM/nFoI_k6GAgAJ

我看到这个问题出现了很多,很多人在文档(包括我自己)中遗漏的是事件总线不使用集群管理器发送事件总线消息。即在Hazelcast作为集群管理器的示例中,您可以正常启动Hazelcast集群(因此您的集群管理器很好);但是,由于以下一个或多个原因,事件总线无法与其他docker实例通信:

  1. 它试图使用不正确的IP地址到另一个节点(即Docker实例上的私有接口的IP,而不是公开映射的IP)。
  2. 它试图在端口上进行通信Docker未配置为转发(如果您未指定,则事件总线选择动态端口)

你需要做的是:

  1. 告诉Vertx其他节点用于与每个实例通信的IP地址(使用-cluster-host [命令行],setClusterPublicHost [VertXOptions]或“vertx.cluster.public.host”[系统属性]选项)
  2. 告诉Vertx明确用于事件总线通信的端口,并确保Docker为这些端口转发流量(使用“vertx.cluster.public.port”[系统属性],setClusterPublicPort [VertXOptions]或-cluster-port [命令行]选项)。在过去,我使用过15701,因为它很容易记住(只是Hazelcast端口的'1')。

事件总线仅使用Cluster Manager来管理其他Vertx实例的IP /端口信息以及消费者/生产者的注册。通信是独立于集群管理器完成的,这就是为什么您可以正确配置集群管理器并进行通信,但仍然没有事件总线通信。

如果两个容器都在同一主机上运行,​​则可能不需要执行上述两个步骤,但一旦开始在不同的主机上运行它们,您肯定会这样做。

也可能发生的事情是,vert.x使用loopback接口,当没有指定vert.x(不是hazelcast)应通过eventbus进行通信的IP时。这里的问题是,你不知道通过哪个接口进行通信(环回,与IP的接口,你甚至可以有多个IP接口)。

为了克服这个问题,我写了一个方法https://github.com/swisspush/vertx-cluster-watchdog/blob/master/src/main/java/org/swisspush/vertx/cluster/ClusterWatchdogRunner.java#L101


3
投票

集群管理器工作正常,集群管理器配置必须在集群中的每个节点(计算机/ docker容器)上相同,或者根本不进行任何配置(使用集群管理器的默认配置)。 您必须在每个节点上使事件总线配置保持一致,您必须将每个节点上的群集主机设置为此节点本身的IP地址和任意端口号(除非您尝试运行超过Vert.x实例)在同一节点上,您必须为每个Vert.x实例选择不同的端口号。 例如,如果节点的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);

1
投票

发现这个solution对我来说很完美,下面是我的代码片段(重要的部分是options.setClusterHost()

public class Runner {

    public static void run(Class clazz) {
        VertxOptions options = new VertxOptions();
        try {
            // for docker binding
            String local = InetAddress.getLocalHost().getHostAddress();
            options.setClusterHost(local);
        } catch (UnknownHostException e) { }

        options.setClustered(true);

        Vertx.clusteredVertx(options, res -> {
            if (res.succeeded()) {
                res.result().deployVerticle(clazz.getName());
            } else {
                res.cause().printStackTrace();
            }
        });
    }
}

public class Publisher extends AbstractVerticle {

    public static void main(String[] args) {
        Runner.run(Publisher.class);
    }

    ...
}

无需定义任何其他内容......

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