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

在我目前的设置中,我使用的是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 ,但我不确定它们与一般网络拓扑的关系。

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

我看到这个问题出现了很多,很多人在文档(包括我自己)中错过的是Event Bus不使用集群管理器发送事件总线消息。 即在您的示例中使用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

集群管理器工作正常,集群管理器配置必须在集群中的每个节点(计算机/ 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); 

发现这个解决方案对我来说非常合适,下面是我的代码片段(重要的部分是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); } ... } 

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