YGC频繁、NettyClient误用的两个Case

写写最近碰到的两个case,一个是关于ygc频繁排查的case,另一个是netty client误用造成的cpu sy高的case。

ygc频繁的case
很多人都问过我多久一次的ygc叫频繁,其实由于ygc通常是非常快的(几十ms或更低),所以通常来说ygc很频繁的发生也不会造成太大的影响,例如我们很多生产系统都是4s左右一次ygc。
ygc频繁是比较难查的,原因是ygc频繁,但通常来说都是ygc后就回收掉了,所以内存dump下来是看不出什么的,对于这个case我给的建议是多jmap -histo [pid]几次,原因是希望多看看在ygc的阶段中产生的对象到底是些什么…
业务方多执行了几次后,很幸运的看到了频繁产生的对象是一个自定义的对象,看到这个后就用btrace去跟了,看看到底是哪里在频繁的产生这个对象。
不过这个排查方法其实并没有通用,例如如果看到频繁产生的是char[],那就非常不好跟了….

netty client误用造成cpu sy高
有一个应用出现了cpu sy非常高的状况,sy大概使用到了60%,对于java应用而言sy如此高通常是由于线程太多,或线程主动切换太多造成的,按照这个思路,先统计了下线程数:ps -eLf | grep java -c,看到结果后,我和我的小伙伴们都惊呆了,1.6w个java线程,对大多数java应用而言,这不是太正常的现象,于是jstack dump看看线程到底什么状况。

jstack dump出来的结果显示,大部分的线程都是Netty I/O Worker线程…

对netty熟一些的同学会知道netty创建一个连接后,会将连接交给后端的NioWorker线程,由NioWorker线程来处理具体的I/O读写事件,NioWorker的线程池的线程数默认为cpu * 2,在上面的场景中创建了1w+的NioWorker线程,那只能是更前端让NioWorker产生了更多的线程数。

往上追朔可以看到NioWorker的线程数要创建更多的话,必然是NioClientSocketChannelFactory每次重新创建了,如每次创建连接时,NioClientSocketChannelFactory重新创建,就会直接导致每次创建的这个连接都会扔到一个新的NioWorker线程去处理。

和业务方确认后,可以看到业务方的代码里确实是在每次创建连接时都重新new NioClientSocketChannelFactory,这就能解释通了。

因此这问题的解决方法也很简单,NioClientSocketChannelFactory创建一个就够了,可以直接static创建一个,然后赋值到每次new的BootStrap里。

不过话说,这一定程度上来说确实是个“坑”,mina也是同样如此,server端由于通常只是启动一个端口监听,所以通常不会出现这现象,对于client而言,这貌似是挺容易犯的一个错。

=============================
题图来源于:http://www.caps-entreprise.com.cn/wp-content/uploads/2012/06/%E6%88%90%E5%8A%9F%E6%A1%88%E4%BE%8B.jpg
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。