记一次线上Curator使用过程JVM栈溢出解决
为了同学们看起来一目了,特按如下思路进行讲解。
1.出现的场景
2.分析及解决的过程
3.总结
最近公司要使用zookeeper做配置管理(后面简称ZK),然后自己就提前用虚拟机进行了ZK三台集群的搭建。之后开始选择使用zookeeper的java client工具,google了半天,发现了一个很名强大的Apache的Curator工具,很多底层的东西都已经给你封装好了,所以用起来很方便,因为我使用的场景是做配置管理,所以使用Curator的Framework就够了。Curator相对于zookeeper,就相当于Guava之于Java.
因为每天的访问量上亿级的,所以考虑的因素还是很多,因此从网上找了一些demo,然后自己就开始写一些测试的类,下边的这个方法是用于获取客户端,并且加入了一些监听和输出:
private static CuratorFramework getClient(String namespace) throws Exception{
ACLProvider aclProvider = new ACLProvider() {
private List<ACL> acl ;
@Override
public List<ACL> getDefaultAcl() {
if(acl ==null){
ArrayList<ACL> acl = ZooDefs.Ids.CREATOR_ALL_ACL;
acl.clear();
acl.add(new ACL(Perms.ALL, new Id("auth", "admin:admin") ));
this.acl = acl;
}
return acl;
}
@Override
public List<ACL> getAclForPath(String path) {
return acl;
}
};
String scheme = "digest";
byte[] auth = "admin:admin".getBytes();
int connectionTimeoutMs = 1000;
String connectString = "127.0.0.1:2181";
CuratorFramework client = CuratorFrameworkFactory.builder().
aclProvider(aclProvider).
authorization(scheme, auth).
connectionTimeoutMs(1).
connectString(connectString).sessionTimeoutMs(50).
namespace(namespace).
retryPolicy(new RetryOneTime(1)).build();
client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
@Override
public void stateChanged(CuratorFramework client, ConnectionState newState) {
System.out.println("** STATE CHANGED TO : " + newState);
}
});
client.start();
client.getZookeeperClient().internalBlockUntilConnectedOrTimedOut();
// client.getZookeeperClient().blockUntilConnectedOrTimedOut();
System.out.println(client.getZookeeperClient().isConnected());
System.out.println(client.getState());
return client;
}
获取客户端之后就可以启动(client.start())客户端并且创建相当的Node以及它的payload. 感觉写的已经可以了,而且经过简单的测试,觉得可以了,然后就上到测试环境上了,测试环境的访问量并不是很大,所以也没有什么特别异常,之后就放到线上了。
当把程序放到线上去之后,系统的JVM监控系统就开始报警,线程数由几百迅速增加到了3、4千个,直接超过了我们设置的报警阈值,所以感觉使用jstack命令 jstack -l pid > threadDump,找一个 stack analyzer online的一个网站 fastthread.io, upload做好的threadDump文件,上边有很多汇总,然后基本上一目了然:

1700多个TIMED_WATING,还有1700多个TIMED_WATING,这里边肯定有问题,然后继续往下拉,会按线程分组进行展示:

会发现有大概有77%的线程和Curator有关系,这个应该就是它的问题了,那么点开里边的内容,就能看到线程的明细了,继续:

里边有Curator Framework的代码了,找到相当的行907,发现只要Client一启动的话就会使得BlockingQueue会有一个take()的动作,这个take的含义是将head取到,如果没有的话就等待,这就是线程WAITING的状态,然后继续看是在什么地方调用的它。

找到了,原来是客户端启动(client.start())的时候进行的调用,因为我在网上看到很多地方说build模式拿到的Client是线程安全的,所以我就每次拿一次client,然后调用其start()。这样每个不同的线程就会都等待在那个位置上。我没有在Finally调用 CloseableUtils.closeQuietly(client); 因为请求量太大,如果频繁的调用关闭客户端会造成性能下降,必须保持一个长连接。

打开Curator的官网上,里边也进行了说明,创建采用build的方式是线程安全的,但是要保持单例。
这样问题找到了,下边开始想着如果修复和优化,首先让它实现单例,同时还不能用完之后就直接关闭。同时要保持长连接,在特定情况下进行连接关闭,那就如果出现异常为
KeeperException.ConnectionLossException时需要捕获并且进行计数和关闭。同时也为了效率考虑,再获取Node的payload时将payload进行缓存,这样再次减少了对zk的大量访问。同时可以根据自己的实际情况去考虑缓存的时间。
if(client == null || client.getState().equals(CuratorFrameworkState.STOPPED) || !client.getNamespace().equals(namespace)) {
synchronized (ZookeeperUtil.class) {
if(client == null || client.getState().equals(CuratorFrameworkState.STOPPED) || !client.getNamespace().equals(namespace)) {
CloseableUtils.closeQuietly(client);
client = getClient(namespace);
}
}
}
同时在网上找到zookeeper集群上从3.4开始,从客户端连接数maxClientCnxns(配置在zoo.cfg)默认连接数为60,改为0时不限制。
总结:
1. 当遇到线程数增加或CPU过高时需要使用jstack将JVM的线程数据导出到文件,然后通过在线工具或自己下载的工具进行分析,我还是比较喜欢这个在线的分析工具,它能分析出总的线程数中按状态进行分析,还可以按线程类型进行分组,很强大。
2. 遇到问题要冷静思考,然后多写几个小的demo进行测试。我其实在写这个问题的过程中我是写了测试类进行模拟的,然后通过本机的jvisualvm查看栈的情况,根我推断的一致的,所以就会找到解决的方法。
3.有些技术知识还是从官方网站学习,而且如果看书的话,需要从头看到尾,这样的话基本上能了解事务的全部内容,否则只看到部分内容。
如果有写的不对的地方,欢迎同学们来拍砖~
记一次线上Curator使用过程JVM栈溢出解决的更多相关文章
- 记一次线上bug排查-quartz线程调度相关
记一次线上bug排查,与各位共同探讨. 概述:使用quartz做的定时任务,正式生产环境有个任务延迟了1小时之久才触发.在这一小时里各种排查找不出问题,直到延迟时间结束了,该任务才珊珊触发.原因主要就 ...
- 解Bug之路-记一次线上请求偶尔变慢的排查
解Bug之路-记一次线上请求偶尔变慢的排查 前言 最近解决了个比较棘手的问题,由于排查过程挺有意思,于是就以此为素材写出了本篇文章. Bug现场 这是一个偶发的性能问题.在每天几百万比交易请求中,平均 ...
- 记一次线上gc调优的过程
近期公司运营同学经常表示线上我们一个后台管理系统运行特别慢,而且经常出现504超时的情况.对于这种情况我们本能的认为可能是代码有性能问题,可能有死循环或者是数据库调用次数过多导致接口运行 ...
- 记一次线上服务CPU 100%的处理过程
告警 正在开会,突然钉钉告警声响个不停,同时市场人员反馈客户在投诉系统登不进了,报504错误.查看钉钉上的告警信息,几台业务服务器节点全部报CPU超过告警阈值,达100%. 赶紧从会上下来,SSH登录 ...
- 记一次排查线上MySQL死锁过程,不能只会curd,还要知道加锁原理
昨晚我正在床上睡得着着的,突然来了一条短信. 啥,线上MySQL死锁了,我赶紧登录线上系统,查看业务日志. 能清楚看到是这条insert语句发生了死锁. MySQL如果检测到两个事务发生了死锁,会回滚 ...
- 记一次线上Kafka消息堆积踩坑总结
2018年05月31日 13:26:59 xiaoguozi0218 阅读数:2018更多 个人分类: 大数据 年后上线的系统,与其他业务系统的通信方式采用了第三代消息系统中间件Kafka.由于是 ...
- 记一次线上由nginx upstream keepalive与http协议"协作"引起的接口报错率飙高事件
年前接到个任务,说要解决线上一些手机客户端接口报错率很高的问题.拿到了监控邮件,粗略一看,各种50%+的错误率,简直触目惊心.这种疑难杂症解决起来还是挺好玩的,于是撸起袖子action. 最终的结果虽 ...
- 【MySQL】记一次线上重大事故:二狗子竟然把线上数据库删了!!
写在前面 估计二狗子这几天是大姨夫来了,心情很郁闷,情绪也很低落,工作的时候也有点心不在焉.让他发个版本,结果,一行命令下去把线上的数据库删了!你没听错:是删掉了线上的数据库!运营那边顿时炸了锅:怎么 ...
- 线上问题debug过程(cat,grep,tr,awk,sort,uniq,comm等工具的综合使用)
问题:发现线上到货单的数量,小于实际到货的数量. 怀疑一些隐藏的条件,将部分唯一码进行了过滤,导致数量变少. 开展了如下的跟踪流程: 1.找到其中一个明细的唯一码 grep 6180e-4b09f p ...
随机推荐
- Java JMS 程序基础 与 ActiveMQ 安装(一)
一 ActiveMQ安装 从Apache官网上下载 ActivieMQ的安装包 apache-activemq-5.9.1-bin.tar.gz, 并拷贝到linux的安装目录解压 # tar -zx ...
- AJAX跨域完全讲解
AJAX跨域完全讲解 今天在慕课网上学习了AJAX跨域完全讲解:https://www.imooc.com/learn/947 我在收集AJAX面试题的时候其实就已经有过AJAX跨域的问题的了,当时候 ...
- 隐藏文件的查看(Win/Linux/macOS)
Windows(10): 点查看->点选项,弹出文件夹选项,点查看,高级设置里找到隐藏文件和文件夹这个选项,按需求选显示或者隐藏即可. Linux: Linux下,类似于.ssh开头的文件或者文 ...
- 老男孩Python全栈开发(92天全)视频教程 自学笔记07
day7课程内容: Python的编码解码 二进制 --->ASCII:只能存英文和拉丁字符,一个字符占一个字节,8位 ------->gb2312:只能6700多个中文,1980年 -- ...
- linux下安装git提示”无法打开锁文件 /var/lib/dpkg/lock - open (13: 权限不够)“
如图所示,输入命令:apt-get install git后提示权限不够 解决方法,在命令前加 sudo即可 sudo apt-get install git sudo是linux系统管理指令,是允许 ...
- EmguCV中图像类型进行转换
1. Bitmap:类型不在 Emgucv命名空间中 2. Image<TColor, TDepth> 3. Mat: 4. UMat: 高 ...
- UVa 11988破损的键盘
这题是很好的学习用数组实现链表的例子. 原题链接 UVa11988 题意 输入一段文本,字符'['表示Home键,']'表示End键.输出屏幕上面的结果. 思路 难点在于在字符串的头和尾插入字符,如果 ...
- uva12563
一个简单的0-1背包,背包容量为t-1,每个物品价值为1,代价为t[i].背包容量为t-1而不是t的原因是留1s唱<劲歌金曲>. AC代码: #include<cstdio> ...
- 关于adb is down 的两个解决方案
在Android开发过程中经常遇到这样的一个问题,The connection to adb is down, and a severe error has occured. 解决方案一: 1.为了以 ...
- redis在windows下的安装
redis服务器端程序:https://github.com/dmajkic/redis/downloads 根据自己的操作系统,选择32位和64位的 解压后文件目录如下 redis-server.e ...