Hazelcast Cluster Manager

翻译:Ranger Tsao,校对 宋子豪、赵亮

HazelcastClusterManager 是基于 Hazelcast 实现 ,是Vert.x 中集群管理器中的默认实现。由于 Vert.x 集群管理的可插拔性,也可轻易切换至其它的集群管理器。

  • Maven(pom.xml)
  1. <dependency>
  2. <groupId>io.vertx</groupId>
  3. <artifactId>vertx-hazelcast</artifactId>
  4. <version>3.4.1</version>
  5. </dependency>
  • Gradle(build.gradle)
  1. compile 'io.vertx:vertx-hazelcast:3.4.1'

Vert.x 集群管理器包含一下几个功能:

  1. 发现并管理集群中的节点
  2. 管理集群端的主题订阅清单(这样就可以轻松得知集群中的那些节点订阅了那些 EventBus 地址)
  3. 分布式 Map 支持
  4. 分布式锁
  5. 分布式计数器

注意事项
Vert.x 集群器并不处理节点之间的通信,在 Vert.x 中节点中的通信是直接由 TCP 链接处理的。

使用 Hazelcast cluster manager

如果通过命令行来使用 Vert.x,对应集群管理器 jar 包( vertx-hazelcast-${version} )应该在 Vert.x 中安装包中。

如果在 Maven 或者 Gradle 工程中使用 Vert.x ,只需要在工程依赖中加上相应的 ClusterManager 实现依赖:io.vertx:vertx-hazelcast:${version}

如果 vertx-hazelcast-${version}classpath 中,Vert.x将自动检测到,并将其作为集群管理。需要注意的是,要确保 Vert.x 的 classpath 中没有其它的 ClusterManager 实现 jar 包。

当然在内嵌 Vert.x 时,通过编程的方式创建 Vert.x 集群模式实例,调用 setClusterManager 方法显式指定集群管理器。

  1. ClusterManager mgr = new HazelcastClusterManager();//创建ClusterManger对象
  2. VertxOptions options = new VertxOptions().setClusterManager(mgr);//设置到Vertx启动参数中
  3. Vertx.clusteredVertx(options, res -> {
  4. if (res.succeeded()) {
  5. Vertx vertx = res.result();
  6. } else {
  7. // failed!
  8. }
  9. });

配置 Hazelcast cluster manager

通常情况下,集群管理器的相关配置是由打包的jar中的默认配置文件 default-cluster.xml 决定的。

default-cluster.xml 还是下面需要提到的 cluster.xml 必须是一个 Hazelcast 配置文件,在 Hazelcast 的官方网站,可以找到具体的配置描述。

如果要覆盖此配置,可以在 classpath 中添加一个 cluster.xml 文件。如果想在 fat jar 中内嵌 cluster.xml ,此文件必须在 fat jar 的根目录中。如果此文件是一个外部文件,则必须将其添加至 classpath 中。举个例子:

  1. # cluster.xml 在当前路径中
  2. java -jar ... -cp . -cluster
  3. vertx run MyVerticle -cp . -cluster
  4. # cluster.xml 在 conf 目录中
  5. java -jar ... -cp conf -cluster

还有一种方式来覆盖默认的配置文件,那就是利用系统配置 vertx.hazelcast.config 来实现:

  1. # 指定一个外部文件为自定义配置文件
  2. java -Dvertx.hazelcast.config=./config/my-cluster-config.xml -jar ... -cluster
  3. # 从 classpath 中加载一个文件为自定义配置文件
  4. java -Dvertx.hazelcast.config=classpath:my/package/config/my-cluster-config.xml -jar ... -cluster

如果 vertx.hazelcast.config 值不为空时,将覆盖 classpath 中所有的 cluster.xml 文件,但是如果加载 vertx.hazelcast.config 失败时,系统将选取 classpath 任意一个 cluster.xml ,甚至直接使用默认配置。

注意:Vert.x 并不支持 -Dhazelcast.config 设置方式,请不要使用。

同时也可以通过编程的形式达到配置的目的:

  1. Config hazelcastConfig = new Config(); //创建hazelcast配置
  2. // 设置相关的hazlcast配置,在这里省略掉,不再赘述
  3. ClusterManager mgr = new HazelcastClusterManager(hazelcastConfig);
  4. VertxOptions options = new VertxOptions().setClusterManager(mgr);
  5. Vertx.clusteredVertx(options, res -> {
  6. if (res.succeeded()) {
  7. Vertx vertx = res.result();
  8. } else {
  9. // failed!
  10. }
  11. });

Hazelcast支持多种不同的传输协议,包括组播和TCP。默认配置中采用组播传输协议,因此您必须在网络上启用组播才能使其工作。

具体详细配置,请参阅 Hazelcast 文档。

使用已存在的 Hazelcast 集群

可以在集群管理器通过设置 HazelcastInstance 来复用现有集群:

  1. HazelcastInstance instance = HazelcastClient.newHazelcastClient(
  2. new ClientConfig()
  3. .setGroupConfig(new GroupConfig("groupname","password")
  4. .setNetworkConfig(new ClientNetworkConfig().addAddress("hosts")))); //创建HazelcastClient
  5. ClusterManager mgr = new HazelcastClusterManager(hazelcastInstance);
  6. VertxOptions options = new VertxOptions().setClusterManager(mgr);
  7. Vertx.clusteredVertx(options, res -> {
  8. if (res.succeeded()) {
  9. Vertx vertx = res.result();
  10. } else {
  11. // failed!
  12. }
  13. });

在这种情况下,Vert.x不是 Hazelcast 群集的所有者,所以不要关闭 Vert.x 时关闭 Hazlecast 集群。

请注意,自定义 Hazelcast 实例需要配置:

  1. <properties>
  2. <property name="hazelcast.shutdownhook.enabled">false</property>
  3. </properties>
  4. <multimap name="__vertx.subs">
  5. <backup-count>1</backup-count>
  6. </multimap>
  7. <map name="__vertx.haInfo">
  8. <time-to-live-seconds>0</time-to-live-seconds>
  9. <max-idle-seconds>0</max-idle-seconds>
  10. <eviction-policy>NONE</eviction-policy>
  11. <max-size policy="PER_NODE">0</max-size>
  12. <eviction-percentage>25</eviction-percentage>
  13. <merge-policy>com.hazelcast.map.merge.LatestUpdateMapMergePolicy</merge-policy>
  14. </map>
  15. <semaphore name="__vertx.*">
  16. <initial-permits>1</initial-permits>
  17. </semaphore>

重要提醒

  • 当 Vert.x 集群使用 HA(高可用或故障转移)时,请不要使用 Hazelcast 客户端,因为他们不会通知他们何时离开集群,同时有可能丢失数据,还有可能将集群置于不一致的状态。更多情况请翻阅 Issue 24
  • 同时要确保 Hazelcast 集群 先于 Vert.x 集群启动,后于 Vert.x 集群关闭。同时需要禁用 shutdownhook。参考上述的 xml 配置,或者通过 系统变量来实现。

使用 Hazelcast async methods

Hazelcast 中的 IMapIAtomicLong 接口(数据结构) 均有异步调用方法,其返回值为 ICompletableFuture<V>,这与 Vert.x 的线程模型完美契合。但是即使这些接口已经存在一段时间,却没有通过 HazelcastInstance 公共 API 暴露。

默认情况下,HazelcastClusterManager 使用公共 API。当在程序启动时,设置选项-Dvertx.hazelcast.async-api=true ,将代表系统在与 Hazelcast 集群通讯交互时,将采用 Hazelcast async API 。这意味着,Counter 计数操作、AsyncMapget put remove 操作都将通过 Vert.x EventLoop 线程来执行,而不是通过 Woker 线程的 vertx.executeBlocking 执行。

故障排除

如果默认的组播配置不能正常运行,通常有以下原因:

机器禁用组播

MacOS 默认禁用组播。Google一下启用组播。

使用错误的网络接口

如果机器上有多个网络接口(也有可能是在运行 VPN 的情况下),那么 Hazelcast 很有可能是使用了错误的网络接口。

为了确保 Hazelcast 使用正确的网络接口,在配置文件中将 interface 设置为指定IP地址,同时确保 enabled 属性设置为 true 。 例如:

  1. <interfaces enabled="true">
  2. <interface>192.168.1.20</interface>
  3. </interfaces>

当运行集群模式时,需要确保 Vert.x 使用正确的网络接口。当通过命令行模式时,可以设置 cluster-host 参数:

  1. vertx run myverticle.js -cluster -cluster-host your-ip-address

其中 your-ip-address 必须与 Hazelcast 中的配置保持一致。

当通过编程模式使用 Vert.x 时,可以调用方法 setClusterHost 来设置参数

使用VPN

VPN 软件通常通过创建不支持组播的虚拟网络接口来进行工作。在 VPN 环境中,如果 Hazelcast 与 Vert.x 不正确配置的话,VPN 接口将被选择,而不是正确的接口。

所以,如果你的软件运行在 VPN 环境中,参考上述章节,设置正确的网络接口。

组播不可用

在某些情况下,因为特殊的运行环境,可能无法使用组播。在这种情况下,应该配置其他网络传输,例如在 TCP 上使用 TCP 套接字,在亚马逊云上使用 EC2 。

有关 Hazelcast 更多传输方式,以及如何配置它们,请咨询 Hazelcast 文档。

开启日志

在排除故障时,开启 Hazelcast 日志,将会给予很大的帮助。在 classpath 中添加 vertx-default-jul-logging.properties 文件(默认的JUL记录时),这是一个标准 java.util.loging(JUL) 配置文件。具体配置如下:

  1. com.hazelcast.level=INFO
  2. java.util.logging.ConsoleHandler.level=INFO
  3. java.util.logging.FileHandler.level=INFO

Hazelcast 日志配置

Hazelcast 的日志默认采用 JDK 实现(参考 JUL)。如果想切换至其他日志库,通过设置 azelcast.logging.type 即可达到目的。

  1. -Dhazelcast.logging.type=slf4j

详细文档请参考 hazelcast documentation

使用其他 Hazelcast 版本

当前的 Vert.x HazelcastClusterManager 使用的 Hazelcast 版本为 3.6.3 。如果开发者想使用其他版本的 Hazelcast,需要做以下工作:

  • 将目标版本的 Hazelcast 依赖添加至 classpath 中
  • 如果是 fat jar 的形式,在构建工具中使用正确的版本

参考代码如下:

  • Maven(pom.xml)
  1. <dependency>
  2. <groupId>com.hazelcast</groupId>
  3. <artifactId>hazelcast</artifactId>
  4. <version>ENTER_YOUR_VERSION_HERE</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>io.vertx</groupId>
  8. <artifactId>vertx-hazelcast</artifactId>
  9. <version>3.4.1</version>
  10. </dependency>
  • Gradle(build.gradle)
  1. dependencies {
  2. compile ("io.vertx:vertx-hazelcast:3.4.1"){
  3. exclude group: 'com.hazelcast', module: 'hazelcast'
  4. }
  5. compile "com.hazelcast:hazelcast:ENTER_YOUR_VERSION_HERE"
  6. }