得物 ZooKeeper SLA 也可以 99.99%

💡 原文中文,约6500字,阅读约需16分钟。
📝

内容提要

ZooKeeper(ZK)是一个分布式应用程序协调服务,通过优化版WatchManagerOptimized解决了WatchManager的内存占用问题,提升了性能和稳定性。

🔎

延伸解读

WatchManager 内存问题的根源

文章指出,ZooKeeper 默认的 WatchManager 使用 WatchTables 和 Watch2Paths 两个 HashMap 存储 ZNode 与 Watcher 的正反映射关系。当 ZNode 和 Watcher 数量较多,尤其是客户端全量订阅时,关系条数呈指数增长,导致巨大内存开销。例如,20 万 ZNode 和 5000 Watcher 可产生 1 亿条关系,仅存储结构就需约 5.9GB 内存。这是自建集群出现 OOM 的主要原因。

WatchManagerOptimized 的优化机制

优化版通过两项关键改进解决内存问题:一是使用 ConcurrentHashMap 和 ReadWriteLock 替代 synchronized 重型锁,提升并发性能;二是采用位图(BitSet)存储 Watcher 关系,将每个关系压缩为位,大幅降低内存占用。例如,1 万个 Watcher 的位图仅需 1.2KB,而 HashSet 需 305KB,存储效率相差近 300 倍。在极端全订阅场景下,内存占用从 5.9GB 降至 11.7MB,相差 516 倍。

性能提升与稳定性收益

JMH 微基准测试显示,优化版在添加 Watch 操作上比默认版快 6.5 倍,触发 Watch 快 5 倍。灰度测试中,多个集群的内存占用降低 89% 至 91%,选举耗时降低 42% 至 64%,读延迟降低 53% 至 95%,提案和传播延迟从数十万毫秒降至毫秒级。这些改进显著提升了 ZooKeeper 的一致性和稳定性,使 SLA 提升一个数量级。

生产环境配置建议

文章建议将 dataDir 和 dataLogDir 挂载到不同磁盘并使用高性能块存储;对于 ZooKeeper 3.8 版本,使用 JDK 17 并启用 ZGC,3.5/3.6 版本可使用 JDK 8 加 G1;将 SnapshotCount 从默认 100,000 调整为 500,000 以降低磁盘压力;并启用 WatchManagerOptimized。这些配置有助于进一步提升集群稳定性。

❓

Q&A

ZooKeeper的主要功能是什么?

ZooKeeper是一个分布式应用程序协调服务,主要用于管理和协调分布式系统中的数据。

得物技术团队如何提升ZooKeeper的SLA?

得物技术团队通过使用阿里的MSE-ZK,达到了99.99%的SLA可靠性,并进行了稳定性加固。

WatchManagerOptimized是如何解决内存占用问题的?

WatchManagerOptimized通过使用位图存储Watcher关系,显著降低内存消耗,并优化了锁的使用效率。

自建ZooKeeper集群出现内存问题的原因是什么?

自建ZooKeeper集群的内存问题主要是由于WatcherManager管理的childWatches和dataWatches占用大量内存。

优化版WatchManager与默认版的性能差异如何?

优化版在内存占用和操作时间上均优于默认版,性能提升可达6.5倍至516倍。

如何配置ZooKeeper以提升系统稳定性?

建议将dataDir和dataLogDir挂载到不同磁盘,并使用高性能块存储,同时调整SnapshotCount参数。

🏷️

标签

➡️

继续阅读