Hazelcast Cluster Manager

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

    • Maven(pom.xml)
    • 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 链接处理的。

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

    如果在 Maven 或者 Gradle 工程中使用 Vert.x ,只需要在工程依赖中加上相应的 ClusterManager 实现依赖:io.vertx${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 决定的。

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

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

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

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

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

    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 文档。

    可以在集群管理器通过设置 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. <property name="hazelcast.shutdownhook.enabled">false</property>
    2. </properties>
    3. <multimap name="__vertx.subs">
    4. <backup-count>1</backup-count>
    5. </multimap>
    6. <map name="__vertx.haInfo">
    7. <max-idle-seconds>0</max-idle-seconds>
    8. <eviction-policy>NONE</eviction-policy>
    9. <max-size policy="PER_NODE">0</max-size>
    10. <eviction-percentage>25</eviction-percentage>
    11. <merge-policy>com.hazelcast.map.merge.LatestUpdateMapMergePolicy</merge-policy>
    12. </map>
    13. <semaphore name="__vertx.*">
    14. <initial-permits>1</initial-permits>
    15. </semaphore>

    重要提醒

    • 当 Vert.x 集群使用 HA(高可用或故障转移)时,请不要使用 Hazelcast 客户端,因为他们不会通知他们何时离开集群,同时有可能丢失数据,还有可能将集群置于不一致的状态。更多情况请翻阅
    • 同时要确保 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 很有可能是使用了错误的网络接口。

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

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

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

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

    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

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

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

    参考代码如下:

    • Maven(pom.xml)
    • 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"