分布式集群管理
你当前正在浏览历史版本 Vert.x 4.4.9 的文档。 访问本页面的 最新版本。

ZooKeeper 集群管理器 (vertx-zookeeper)

该组件为 Vert.x 提供了基于 Apache ZooKeeper 的集群管理器(Cluster Manager)实现。

该实现完整对接了 Vert.x 的集群 SPI 规范,因此你可以使用它直接替代 vertx-hazelcast 作为集群底座。 在项目构建描述文件中添加以下依赖:

  • Maven(在 pom.xml 中):

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-zookeeper</artifactId>
  <version>5.0.12</version>
</dependency>
  • Gradle(在 build.gradle 文件中):

compile 'io.vertx:vertx-zookeeper:5.0.12'

在 Vert.x 中,集群管理器承担以下核心协作职责:

  • 集群中 Vert.x 节点的自动发现与成员拓扑维护

  • 维护全集群范围的 Event Bus 主题订阅者映射表(以便获知哪些节点对哪些 Event Bus 地址感兴趣)

  • 分布式映射(Distributed Map)支持

  • 分布式锁(Distributed Locks)

  • 分布式计数器(Distributed Counters)

请注意:集群管理器并不负责节点间的 Event Bus 实际消息传输;节点间的数据通信由 Vert.x 直接通过底层的 TCP 连接通道高效完成。

运行机制原理

本模块底层基于成熟的 Apache Curator 框架封装,而非直接裸调 ZooKeeper 原始客户端。因此项目隐式依赖了 Curator 所需的类库,如 guava、slf4j 以及 zookeeper 客户端。

由于 ZooKeeper 采用树状分层目录结构存储元数据,我们以根路径作为隔离命名空间(Namespace)。默认根路径在 default-zookeeper.json 中配置为 io.vertx。 此外,还有 5 个子路径用于支撑 Vert.x 集群管理器的各项运行时功能(除根命名空间外,其余子路径通常由框架内部管理):

  • /io.vertx/cluster/nodes/:记录所有活跃的 Vert.x 集群节点信息

  • /io.vertx/asyncMap/$name/:记录通过 io.vertx.core.shareddata.AsyncMap 接口创建的异步分布式映射数据

  • /io.vertx/asyncMultiMap/$name/:记录通过 io.vertx.core.spi.cluster.AsyncMultiMap 接口创建的异步多值映射数据

  • /io.vertx/locks/:维护分布式锁状态

  • /io.vertx/counters/:维护全局分布式计数器

使用 ZooKeeper 集群管理器

如果你使用 Vert.x 命令行工具启动应用,需确保将对应的 jar 包(如 vertx-zookeeper-5.0.12.jar)放置在 Vert.x 安装目录下的 lib 目录中。

在基于 Maven 或 Gradle 的工程中,只需直接引入依赖 io.vertx:vertx-zookeeper:5.0.12 即可。

当该 jar 包存在于应用的类路径(Classpath)中时,Vert.x 在启动集群模式时将自动检测并将其激活为默认集群管理器。 请确保类路径中没有其他集群管理器实现,否则 Vert.x 可能会错误加载其他的集群实现。

若通过代码方式嵌入式启动 Vert.x,可以通过配置选项显式传入该集群管理器:

ClusterManager mgr = new ZookeeperClusterManager();
Vertx.builder()
  .withClusterManager(mgr)
  .buildClustered().onComplete(res -> {
  if (res.succeeded()) {
    Vertx vertx = res.result();
    // 集群 Vert.x 实例就绪
  } else {
    // 启动失败!
  }
});

配置 ZooKeeper 集群管理器

集群管理器默认加载打包在 jar 内部的 default-zookeeper.json 配置文件。

若需覆盖默认配置,可以在类路径根目录下提供自定义的 zookeeper.json 文件。 如果将应用打包为可执行 Fat Jar,zookeeper.json 必须位于 Fat Jar 的根路径下;若使用外部配置文件,必须将包含该文件的 目录 追加到类路径中。例如,配合 Vert.x 启动器(Launcher)使用时配置如下:

# 如果 zookeeper.json 位于当前目录:
java -jar ... -cp . -cluster
vertx run MyVerticle -cp . -cluster

# 如果 zookeeper.json 位于 conf 目录下:
java -jar ... -cp conf -cluster

另一种更灵活的覆盖方式是通过系统属性 vertx.zookeeper.config 直接指定外部文件路径:

# 加载文件系统中的外部绝对/相对路径配置:
java -Dvertx.zookeeper.config=./config/my-zookeeper-conf.json -jar ... -cluster

# 或者加载类路径中指定包下的配置文件:
java -Dvertx.zookeeper.config=classpath:my/package/config/my-cluster-config.json -jar ... -cluster

当系统属性 vertx.zookeeper.config 存在时,其优先级高于类路径下的任何 zookeeper.json;若根据该系统属性加载失败,系统将平滑降级至 zookeeper.json 或默认配置。

详细的配置项说明请参阅 default-zookeeper.json 中的内置注释。

你也可以完全通过代码以编程方式构造配置:

JsonObject zkConfig = new JsonObject();
zkConfig.put("zookeeperHosts", "127.0.0.1:2181");
zkConfig.put("rootPath", "io.vertx");
zkConfig.put("retry", new JsonObject()
    .put("initialSleepTime", 3000)
    .put("maxTimes", 3));

ClusterManager mgr = new ZookeeperClusterManager(zkConfig);

Vertx.builder()
  .withClusterManager(mgr)
  .buildClustered().onComplete(res -> {
  if (res.succeeded()) {
    Vertx vertx = res.result();
  } else {
    // 启动失败!
  }
});

可以在 JSON 中自由定制重试策略(Retry Policy):

{
  "retry": {
    "policy": "exponential_backoff"
  }
}

支持的重试策略策略值包括:

  • exponential_backoff(默认:指数退避)

  • bounded_exponential_backoff(有上限的指数退避)

  • one_time(单次重试)

  • n_times(固定 N 次重试)

  • forever(持续重试)

  • until_elapsed(直到超时)

你还可以通过系统属性 vertx.zookeeper.hosts 快速覆盖 ZooKeeper 服务器连接地址。

开启调试日志

在排查 ZooKeeper 集群组网问题时,查看 ZooKeeper 的详细运行时日志非常有帮助。若使用默认的 JUL 日志,可以在类路径下添加 vertx-default-jul-logging.properties 文件,并设置如下级别:

org.apache.zookeeper.level=INFO

同时启用控制台或文件输出处理器:

java.util.logging.ConsoleHandler.level=INFO
java.util.logging.FileHandler.level=INFO