得物 Zookeeper SLA 也可以 99.99% | 得物技术

一、背景

ZooKeeper(ZK)是一个诞生于2007年的分布式应用程序协调服务。尽管出于一些特殊的历史原因,许多业务场景仍然不得不依赖它。比如,Kafka、任务调度等。特别是在 Flink 混合部署 ETCD 解耦 时,业务方曾要求绝对的稳定性,并强烈建议不要使用自建的 ZooKeeper。出于对稳定性的考量,采用了阿里的 MSE-ZK。自从 2022 年 9 月份开始使用至今,我们没有遇到任何稳定性问题,SLA 的可靠性确实达到了 99.99%。

在 2023 年,部分业务使用了自建的 ZooKeeper(ZK)集群,然后使用过程中 ZK 出现了几次波动,随后得物 SRE 开始接管部分自建集群,并进行了几轮稳定性加固的尝试。接管过程中我们发现ZooKeeper在运行一段时间后,内存占用率会不断增加,容易导致内存耗尽(OOM)的问题。我们对这一现象非常好奇,因此也参与了解决这个问题的探索过程。

二、探索分析

确定方向

在排查问题时,我们非常幸运地发现了一个测试环境的故障现场,该集群中的两个节点恰好处于OOM的边缘状态。

图片

有了故障现场,那么一般情况下距离成功终点只剩下50%。

内存偏高,按以往的经验来看,要么是非堆,要么是堆内有问题。从火焰图和jstat 都能证实:是堆内的问题。

图片

图片

如图所示:说明 JVM 堆内存在某种资源占用了大量的内存,并且FGC都无法释放。

内存分析

为了探究 JVM 堆中内存占用分布,我们立即做了一个JVM堆Dump。分析发现 JVM 内存被 childWatches 和 dataWatches 大量占用。

图片

图片

dataWatches:跟踪 znode 节点数据的变化。

childWatches:跟踪 znode 节点结构(tree)的变化。

childWatches和dataWatches同源于WatcherManager。

经过资料排查,我们发现 WatcherManager 主要负责管理 Watcher。ZooKeeper(ZK)客户端首先将 Watcher 注册到 ZooKeeper 服务器上,然后由 ZooKeeper 服务器使用 WatcherManager 来管理所有的 Watcher。当某个 Znode 的数据发生变更时,WatchManager 将触发相应的 Watcher,并通过与订阅该 Znode 的 ZooKeeper 客户端的 socket 进行通信。随后,客户端的 Watch 管理器将触发相关的 Watcher 回调,以执行相应的处理逻辑,从而完成整个数据发布/订阅流程。

图片

进一步分析WatchManager,成员变量 Watch2Path、WatchTables 内存占比高达 (18.88+9.47)/31.82 = 90%。

图片

而 WatchTables、Watch2Path 存储的是 ZNode 与 Watcher 正反映射关系,存储结构图所示:

图片

WatchTables【正向查询表】

HashMap<ZNode, HashSet<Watcher>>

场景:某个ZNode发生变化,订阅该ZNode的Watcher会收到通知。

逻辑:用该ZNode,通过 WatchTables 找到对应的所有 Watcher 列表,然后逐个发通知。<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值