成功升级ZooKeeper:兼容性与性能实践探索

在之前的一篇文章中有提到,我们作了一些ZooKeeper上的资源管理实践。

其中,涉及到的ZooKeeper资源访问和配额控制,都需要高版本的ZooKeeper才能支持,例如硬规则Quota需要3.7.0版本,Quota Metrics to Prometheus需要3.8.0版本。

But,我们的ZK版本是3.4.9

因此,我们需要对ZooKeeper进行升级。

ZK使用场景

目前我们对于ZK的使用场景很多,包含服务注册与发现、数据同步与一致性保证、分布式锁等。

但是总体来看,可以分为两大类:

  • 跨服务协同,涉及服务间的数据同步和一致性需求,例如Dubbo,存在Provider和Consumer,不是在同一个服务里;

  • 单服务跨节点协同,往往是单服务分布式部署所带来的数据一致性需求,例如ElasticJobs、分布式锁、ID生成等。

ZK升级策略

对于不同类型的使用场景,我们可以采用不同的策略。

影响范围

  • 跨服务协同,主要以Dubbo为主,框架成熟稳定,其本身不会带来ZK资源问题,同时该适用场景涉及所有业务及基础服务的注册及发现,影响面较大。因此,对于这部分适用场景~不建议升级~,以稳定为主。

  • 单服务跨节点协同,这类场景更多是限制在单个服务内的,升级的影响范围可用,且可以不用做数据迁移。因此,我们直接创建一个新的ZK节点,将这部分使用场景~直接迁移到新版本ZK~。

目标版本

由于我们的ZK管理规则需要使用到硬规则QuotaQuota Metrics,所以计划升级到最新的3.8.1版本。

升级方案

综上所述,我们需要创建一个3.8.1版本的新ZooKeeper集群,并将单服务跨节点协同场景下的业务服务迁移到新的ZK集群上。

那么,在这个过程就会有非常多的因素需要考虑,其中最主要的就是兼容性以及性能评估。

升级兼容性

在考虑ZK兼容性时,我们主要从三个维度来考虑。

  1. ZK Server兼容性;
  2. ZK Client兼容性;
  3. Apache Curator兼容性。

这里你可能会有疑问,考虑Server、Client兼容性时合理的,那么Apache Curator又是什么?为什么要考虑Apache Curator的兼容性呢?

1
Apache Curator 是一个用于 Apache ZooKeeper 的 Java/JVM 客户端库,用于分布式协调服务,它包含一个高级 API 框架和一些实用程序,可以使ZK更加易用和可靠,它还包括用于常见用例的配方和扩展,例如服务发现和 Java 8 异步 DSL。

综上所诉,Curator是ZK Client的高级封装API,并提供了通用内容的封装和扩展。

在我们的业务服务及部分依赖框架中,都是通过Curator来操作ZK的,我们并不确定低版本Curator是否兼容高版本ZK Server,所以也需要考虑其兼容性。

Curator 版本: org.apache.curaotr:curator-client:2.10.0/2.12.0 org.apache.curaotr:curator-framework:2.10.0/2.12.0 org.apache.curaotr:curator-recipes:2.10.0/2.12.0

ZK Client 版本: org.apache.zookeeper:zookeeper:3.4.8

ZK Server 版本: Apache ZooKeeper:3.4.8

当Server需要升级到3.8.1时,不确定Curator 2.12是否兼容3.8.1的Server。

那么,我们一个个来看看他们的兼容性。

Server及Client兼容性

ZK官方提供了过往版本的Release Note,并且默认对前两个大版本的Server、Client进行兼容性测试,以最新两个版本的Release Note为例,我们来看看具体内容。

1
2
3
4
5
6
7
8
9
10
11
12
7 March, 2022: release 3.8.0 available

1. Log4j1 改为 Logback
2. Read Key/Trust store password from file (and other security related improvements)
3. 支持从OSGI恢复
4. 聚合Prometheus性能指标
5. 升级更新有CVE披露漏洞的第三方依赖

兼容性:
1. ZK clients从3.5.x起完全兼容3.8.x server
2. ZK clients 3.8.x 与3.5.x、3.6.x和3.7.x server的旧接口兼容,新接口无法使用
3. ZK从3.6.x和3.7.x升级到3.8.x可正常升级,无特定的额外操作需要处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
27 March, 2021: release 3.7.0 available
1. 新接口从Java启动ZK server
2. Quota强制执行
3. SASL认证时的主机名规范化
4. Support for BCFKS key/trust store format
5. 可选的强制身份验证
6. “whoami” API
7. 可选的禁用digest 认证
8. SuperUser多重认证
9.  快速感知请求限流(新增错误码ZTHROTTLEDOP)
10. 增加额外的安全指标
11. C、Perl客户端增加SASL支持
12. 增加新的zkSnapshotComparer工具
13. 备注如何通过YCSB工具压测ZK

兼容性:
1. ZK clients从3.5~3.6分支都完全兼容3.7 server
2. ZK clients 3.7.x 与3.5.x、3.6.x server的旧接口兼容,新接口无法使用
3. ZK从3.6.x到3.7可正常升级,无特定的额外操作需要处理

其中,3.7、3.8都对过往2~3个大版本Server、Client的升级兼容性做了测试。

  • Server层面完全兼容,无需额外操作可直接升级。
  • Client层面旧接口完全兼容,新特性使用需要升级Client。

由于我们的ZK从旧版本升级到新版本,不涉及新特性的使用,其向下兼容的特性无需我们做额外的工作。

但是,我们的版本升级跨度比较大,所以还是对常见的Client操作进行了测试,包含ZNode基础操作、Client监听事件、ZNode子节点监听事件、ACL、quota、事务等,初步判断旧版本Client可以兼容新版本Server

Apache Curator兼容性

Apache Curator包含多个模块,以不同的制品发布,每个模块也提供不同的内容。

GroupID/Org ArtifactID/Name Description
org.apache.curator curator-recipes ZooKeeper 分布式协调服务的所有配方。
org.apache.curator curator-async 包含 O/R 建模、迁移等许多功能的异步 DSL。
org.apache.curator curator-framework Curator Framework 高级 API。它是建立在客户端之上并应该会自动引入客户端。
org.apache.curator curator-client Curator Client,它取代了 ZK 分发中的 ZooKeeper Class。
org.apache.curator curator-test 包含 TestingServer、TestingCluster 和其他几个有用的测试工具。
org.apache.curator curator-examples 各种 Curator 特性使用示例。
org.apache.curator curator-x-discovery 基于 Curator Framework 构建的服务发现实现。
org.apache.curator curator-x-discovery-server 一个 RESTful 服务器,可以与 Curator Discovery 一起使用。

我们主要使用的是Curator Client、Curator Framework,所以需要针对这两个模块进行兼容性测试。

在测试方案上,我们通过改写两个模块的测试用例,将原有的2.10.0版本中测试用例里的Mock ZooKeeper Server改为直连3.8.1的ZK Server,并调试验证这批官方测试用例在3.8.1 Server上是否能正常执行,以此来判断其兼容性。

最终运行情况如下:

除部分需要验证ZK集群功能的用例失败外,其他测试用例均运行通过,证明Curator 2.10.0版本是兼容ZK Server 3.8.1的。

性能测试

在我们的使用场景里,ZK的使用场景并不多,但是都比较重要,用于服务注册发现、数据一致性等,整体线上负载并不高。

从收发包可以看出,基本都是心跳包为主。

但是介于我们之前出现过节点数突增及大节点的问题,所以也计划对新的3.8.1进行压测,评估影响。

压测工具 - YCSB

在ZK的官方文档中,在Tools模块推荐了对应的Benchmark工具 - YCSB,其提供了比较完整的压测能力,比如造数、发压、基础数据统计分析能力等。

  • Workload

在发压能力上,它提供了预定义的工作负载Workload,不同的负载属性不同。

类型 说明
Workload A Update heavy workload, 50/50 reads and writes
Workload B Read mostly workload, 95/5 reads/write mix
Workload C Read only, 100% read
Workload D Read latest workload, the most recently inserted records are the most popular
Workload E Short ranges, short ranges of records are queried, instead of individual records
Workload F Read-modify-write, client will read a record, modify it, and write back the changes

除了预定义的工作负载外,也支持通过参数、插件进行自定义,可以根据需要进行设置。

  • Core properties

在参数上,也提供了比较丰富的支持,可以自定义造数模型及数量、发压配置和数据统计、测量类型等。

基础环境及架构

我们线上的ZK集群很小,单个集群3~5节点,单节点配置4C16GB,从ZK Client 到 ZK Server之间的链路也比较简单。

我们的线上环境部署在阿里云上,在中间有一层SLB负载均衡,缓解了客户端连接的压力,实际到单个ZK节点的连接数在1100~1200左右。

基础场景测试

单节点直连场景,在ZK推荐节点大小(不超过1K)的场景下,单ZK Server的节点读OPS可达至少15000,但是此时性能也开始出现下降,平均响应时间及99线均快速上涨。

大节点操作场景测试

在ZK Node较大的场景下,可以看到首先出现问题的是网络和磁盘,内网SLB流量达到瓶颈,磁盘由于频繁的大节点更新,datalog快速膨胀,磁盘被打满。

因此,是需要关注或限制大节点使用的,同时对于频繁写/更新的场景,需要关注磁盘及网络IO状态。

百万节点操作场景测试

在节点超过百万后,对ZK整体的性能并没有什么影响,这也是由于ZK本质上是一个KV存储。

节点批量删除

网上有很多文章都说了ZK这个参数上的坑,这次也实际遇到了,由于删除

总结

综上所述,我们将ZooKeeper从3.4.9升级到3.8.1版本,升级策略是通过将部分合适的业务场景直接迁移到新ZK上,避免了数据迁移,同时我们也做了基于Client、Server以及Apache Curator的兼容性测试,判断完全兼容可进行迁移。

目前我们已经完成部分服务的迁移试点,未发现新的问题。