bigywater.tech
ZooKeeper · 106

Spring Cloud 与 ZooKeeper

Spring Cloud 对 ZooKeeper 的支持只有两件事:服务注册发现(基于 Curator ServiceDiscovery)和配置中心(监听 /config 下的节点)。这篇真起 Spring Boot 应用,看它写了哪些节点、数据长什么样、实例消失与配置变化各要多久。

/services/<应用>/
Spring Cloud 的注册路径(临时节点,数据是 Curator JSON)
21 s
kill -9 后实例从 ZooKeeper 消失(会话协商 20 s)
31 ms
改一个 /config 节点后应用 Environment 的生效时间

注册

实测 · 本机执行输出
  services
    demo-svc
      cd71b2da-fbcf-4262-aec8-08914432476a  [临时节点]
  /services/demo-svc/<uuid> 的数据: {"name":"demo-svc","id":"cd71b2da-fbcf-4262-aec8-08914432476a","address":"<本机局域网IP>","port":7971,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"demo-svc","name":"demo-svc","metadata":{"instance_status":"UP"}},"registrationTimeUTC":1790834215398,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}
  应用自己看到的 /services: ["demo-svc"] | /instances/demo-svc: ["<本机局域网IP>:7971 id=cd71b2da-fbcf-4262-aec8-08914432476a"]

节点格式是 Curator 的 ServiceDiscovery 约定,和Dubbo 的 /dubbo、/services 布局不是一回事(Dubbo 3 的应用级注册也用 /services 路径,但 JSON 的 payload 是 Dubbo 自己的类)。IP 已替换成 <本机局域网IP>。

实例消失

实测 · 本机执行输出
  两个应用与 ZooKeeper 之间会话的协商超时(cons 的 to=): ['10000', '20000'] (tickTime=1000 时服务端 maxSessionTimeout = 20000)
  7971 看到: ["<本机局域网IP>:7971 id=cd71b2da-fbcf-4262-aec8-08914432476a","<本机局域网IP>:7972 id=7f792f17-8cf2-41ea-a0f7-5846b3309456"]
  7972 看到: ["<本机局域网IP>:7971 id=cd71b2da-fbcf-4262-aec8-08914432476a","<本机局域网IP>:7972 id=7f792f17-8cf2-41ea-a0f7-5846b3309456"]
  kill -9 后:ZooKeeper 里的节点 20.6 s 后消失;7971 的 DiscoveryClient 在 20.6 s 后只剩 1 个实例

原因与服务发现那篇相同:没有主动注销就靠会话过期。需要更快,要缩短 spring.cloud.zookeeper.session-timeout(我没有改它,没有验证改后的效果)。

配置

实测 · 本机执行输出
  建之前 /cfg = <unset>
  新建节点后 /cfg 变成 v1:27 ms
  改成 v2:31 ms
  应用运行中再建 /config/application/demo.msg=GLOBAL 后 /cfg = v2 (不能说明优先级:这个全局目录在应用启动时并不存在,可能根本没有被监听)
  重启应用后(此时 /config/application/demo.msg=GLOBAL 与 /config/demo-svc/demo.msg=v2 同时存在)/cfg = v2 (优先级:应用专属配置压过全局)
  /config 的树:
    application
      demo.msg
    demo-svc
      demo.msg

推送机制就是配置中心那篇的 watch;Spring 在这之上做了属性源合并。

分步演示

Spring Cloud ZooKeeper
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。Spring Boot 3.3.5、Spring Cloud 2023.0.4(spring-cloud-zookeeper 4.1.x,经 Maven 代理下载)、ZooKeeper 3.9.6 客户端,OpenJDK 17;应用自己写了 /hello /cfg /instances 三个接口;输出里的本机局域网 IP 已替换为 <本机局域网IP>
    • 没有验证:session-timeout 等配置项改变后的效果、Spring Cloud LoadBalancer 在实例变化时的行为、/config 下 profile 后缀目录(demo-svc,prod)的规则、@RefreshScope Bean 的刷新、ZooKeeper 不可用时应用的启动行为(fail-fast)
    京ICP备2026067502号-1京公网安备11010502063487号