zookeeper OOM问题排查

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:

背景

最近折腾的数据库同步项目中,大量使用了zookeeper(版本3.3.3),可以说是强依赖,但是最近频频出现zookeeper内存使用率达到100%,而且是GC不掉,直接导致整个系统挂起,伤不起阿

 

分析

因为大部分的情况都是无法GC回收,所以很大程度上怀疑出现memory leak。

设置了jvm参数,收集了一下OOM导致jvm crash之后的日志文件进行分析


1.-XX:+HeapDumpOnOutOfMemoryError  

leak分析: 



 

从leak分析来看,比较明显,99%的内存都被Leader类的observingLearners给吃光了,所以重点就可以落在zookeeper observer的使用上了。

zookeeper的observer模式

官方说明: http://zookeeper.apache.org/doc/trunk/zookeeperObservers.html 

主要用于解决读扩展性的问题,observer的节点不参与vote,也就是说写操作都只会发生在leader/follower中进行投票决策,而observer就是一个只读镜像。

但有一点和数据库的master/slave模式不同的是,observer也会接受写请求,但会将请求转交给leader/follower集群进行处理,并同步等待返回结果。

 

可以说observer比较巧妙的解决了读扩展性的问题,在zookeeper3.4.5版本,增加了readonlymode,和observer模式还是有所不同。

 

在我之前的文章中,zookeeper项目使用几点小结,有描述在项目中使用observer的情况: 


从图中可以看出: 

1.  整个zookeeper大集群有2部分组成,杭州的一个leader/follower集群  +  美国的一个observer集群

2.  为保证可用性,杭州集群的机器分别部署在3个机房中,(满足任意机房AB, 机房A+机房B  >  机房A+机房B+机房C/2),最小的部署结构为3+2+2机器,这样可以确保,任何一个机房挂了,都可以保证整个zookeeper集群的可用性

 

代码分析:

有了以上的背景分析,再回到memory leak问题上来,翻了下zookeeper issue,发现还真有提交对应的memory leak问题,https://issues.apache.org/jira/browse/ZOOKEEPER-1303 

看完issue后,这时候问题已经明显了。 

 

在Leader.java类中:


1./** 
2.     * Remove the learner from the learner list 
3.     *  
4.     * @param peer 
5.     */  
6.    void removeLearnerHandler(LearnerHandler peer) {  
7.        synchronized (forwardingFollowers) {  
8.            forwardingFollowers.remove(peer);              
9.        }          
10.        synchronized (learners) {  
11.            learners.remove(peer);  
12.        }  
13.    }  

这里面Leader节点,在与对应的follower/observer之间的链接异常断开时,会清理当前内存中的引用句柄 (不然下次的vote信息还会发送到挂了的节点上)。

而leader在往observer上推送write数据,会遍历当前内存中的observingLearners列表


1./** 
2.     * send a packet to all observers      
3.     */  
4.    void sendObserverPacket(QuorumPacket qp) {          
5.        synchronized(observingLearners) {  
6.            for (LearnerHandler f : observingLearners) {                  
7.                f.queuePacket(qp);  
8.            }  
9.        }  
10.    }  

再看一下LearnerHandler.java类中:


1.public class LearnerHandler extends Thread {  
2.  
3.public void run() {  
4.    p = queuedPackets.poll();  
5.    ........  
6.}  
7.void queuePacket(QuorumPacket p) {  
8.        queuedPackets.add(p);  
9.    }  
10.  
11.}  

LearnerHandler中的处理方式是一种典型的异步处理,通过queuedPackets接受任务数据,然后线程异步进行消费处理。 因为observer可能因为网络抖动,会断开与Leader之间的链接,就会触发shutdown方法。而shutdown方法就是尝试将自己从Leader的observer句柄中移除

 

所以整个问题原因已经比较明确,removeLearnerHandler没有清理observer队列中的句柄,导致一直进行queuePacket调用,又没有异步线程进行消费,所以暴内存是迟早的事。

 

总结

特别注意:3.3.6中居然没修复这个问题,所以可升级zookeeper至3.4.5, 经过实际验证大家可放心升级(我的client 3.3.6 , server 3.4.5)

 

zookeeper 3.4和3.3的兼容性描述: http://blog.cloudera.com/blog/2011/11/apache-zookeeper-3-4-0-has-been-released/

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
3月前
|
缓存 Java 中间件
jvm性能调优实战 -55RPC调用引发的OOM故障
jvm性能调优实战 -55RPC调用引发的OOM故障
58 0
|
Arthas 监控 Cloud Native
用 Arthas 神器来诊断 HBase 异常进程
HBase 集群的某一个 RegionServer 的 CPU 使用率突然飙升到百分之百,单独重启该 RegionServer 之后,CPU 的负载依旧会逐渐攀上顶峰。多次重启集群之后,CPU 满载的现象依然会复现,且会持续居高不下,慢慢地该 RegionServer 就会宕掉,慢慢地 HBase 集群就完犊子了。
用 Arthas 神器来诊断 HBase 异常进程
|
5月前
分布式系列教程(25) -解决Zookeeper启动失败的问题
分布式系列教程(25) -解决Zookeeper启动失败的问题
135 0
|
4月前
|
存储 监控 网络协议
Zookeeper监控之四字监控
Zookeeper监控之四字监控
62 0
|
10月前
|
监控 NoSQL Dubbo
一次zookeeper Curator客户端导致JVM OOM问题的分析记录
一次zookeeper Curator客户端导致JVM OOM问题的分析记录
179 0
|
11月前
|
Shell Apache
Apache ZooKeeper - 线上系统日志清理
Apache ZooKeeper - 线上系统日志清理
159 0
|
Cloud Native Dubbo Java
ZooKeeper 避坑实践: Zxid溢出导致集群重新选主
微服务引擎 MSE 面向业界主流开源微服务项目, 提供注册配置中心和分布式协调(原生支持 Nacos/ZooKeeper/Eureka )、云原生网关(原生支持Higress/Nginx/Envoy,遵循Ingress标准)、微服务治理(原生支持 Spring Cloud/Dubbo/Sentinel,遵循 OpenSergo 服务治理规范)能力。
ZooKeeper 避坑实践: Zxid溢出导致集群重新选主
|
消息中间件 存储 监控
性能调优|生产环境kafka集群400W/tps为啥就扛不住了?
性能调优|生产环境kafka集群400W/tps为啥就扛不住了?
性能调优|生产环境kafka集群400W/tps为啥就扛不住了?
|
消息中间件 存储 运维
记一次 Kafka 重启失败问题排查
由于 A 主题 34 分区的 leader 副本在 broker0,另外一个副本由于速度跟不上 leader,已被踢出 ISR,0.11 版本的 kafka 的 unclean.leader.election.enable 参数默认为 false,表示分区不可在 ISR 以外的副本选举 leader,导致了 A 主题发送消息持续报 34 分区 leader 不存在的错误,且该分区还未消费的消息不能继续消费了。
301 0
记一次 Kafka 重启失败问题排查
|
监控 Java 网络安全
JMX监控zookeeper
JMX监控zookeeper
7119 0