一、系统需求:
保证后台系统在大并发下正常处理每一个业务连接请求。
二、运作方式:
Netty+tomcat。在tomcat的web.xml配置文件中配置一个Listener类用来在tomcat初始化启动时,启动一个Netty服务端,在Netty服务端的Handler中处理每一个连接请求的复杂业务。
三、使用版本:
netty版本:netty-all-5.0.0.Alpha1
jdk版本:Java: 版本 1.7.0_45
tomcat版本:apache-tomcat-8.0.9
四、运作说明:
使用Netty的高并发性能来处理大量的TCP长连接请求,客户端连接到Netty服务端之后,在Handler中调用web应用中相应的类进行处理。
五、出现问题:
收包一段时间(今天测试五个线程同时发,每个线程发送两万左右的数据包,总共大概十万数据包)以后,就会出现tomcat死机状态,日志了不再有任何输出,运行在同一个tomcat上的其他web工程都不能使用了,为什么由tomcat启动的netty协同工作接收大概十万数据包之后出现tomcat假死状态呢?
开源中国提问地址:求问,netty导致tomcat假死
六、问题分析:
6.1,监视线程工具1:jconsole 功能:监控堆内存使用量,线程数,类数量,CPU占用率等. 所在路径:${java安装路径}Java\jdk1.8.0_74\bin
6.2,监视线程工具2:jvisualvm 功能:同jconsole 所在路径:${java安装路径}Java\jdk1.8.0_74\bin
jvisualvm监控图:
6.3,dump堆内存文件方法:
方法1、在jvisualvm界面的监视选项卡的,点击“堆 Dump” 按钮即可生成heapdump文件;
方法2、使用命令jmap -dump:format=b,file=HeapDump.bin <pid>生成(会在界面中显示文件路径),需要查看目标线程的pid(可以查看任务管理器,或者在jconsole或者jvisualvm 工具中查看)。
6.4,dump文件分析工具:MAT(MemoryAnalyzer-1.5.0.20150527-win32.win32.x86_64),打开该软件对6.3中dump出来的dump文件进行分析,可以查看到当前状态下堆内存的使用,以及类的应用情况。
MAT分析结果图:
得到分析结果DefaultEventExecutor占比较高,可能是其出现问题
6.5,对每一个web应用进行监控(找到问题):
1、将javamelody.jar和jrobin-1.5.9.1.jar两个jar包放到web应用的lib中;
2、在web目录下的web.xml文件中加入如下xml片段。
<!-- tomcat监控 -->
<filter>
<filter-name>monitoring</filter-name>
<filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>monitoring</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>net.bull.javamelody.SessionListener</listener-class>
</listener>
3、在浏览器中访问http://localhost:8080/IoT_Harbor/monitoring?period=jour 即可得到当前web应用的监控图,以及所有线程的当前状态。
4、得到正常运行与异常时的线程状态图:
正常状态时:
异常时:
5、对比分析正常运行与异常时所有线程状态发现,后端的NIO线程被阻塞,而执行方法为log4j.
七、找到问题:
测试启动的多个线程,每个线程的测试发包速度为50ms,每次收到数据包Netty的Handler线程中均要对接收数据进行日志打印或者控制台输出,会进行频繁的IO操作,而IO操作会相对耗时。Netty的IO处理线程池,如果遇到非常耗时的业务会很容易把后端的NIO线程给挂死、阻塞。
八、解决方法:
对于复杂的后端业务,分派到专门的业务线程池里面,进行异步回调处理。