Dubbo服务内存溢出,无法创建本地线程问题的解决方案
异常情况
项目使用Dubbo微服务框架开发后端服务。在服务开启后一小时左右,开始拒绝服务并循环抛出该异常:
com.alibaba.dubbo.remoting.ExecutionException: class com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler error when process caught event .
at com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler.caught(AllChannelHandler.java:67)
at com.alibaba.dubbo.remoting.transport.AbstractChannelHandlerDelegate.caught(AbstractChannelHandlerDelegate.java:44)
at com.alibaba.dubbo.remoting.transport.AbstractChannelHandlerDelegate.caught(AbstractChannelHandlerDelegate.java:44)
at com.alibaba.dubbo.remoting.transport.AbstractPeer.caught(AbstractPeer.java:127)
at com.alibaba.dubbo.remoting.transport.netty.NettyHandler.exceptionCaught(NettyHandler.java:112)
at com.alibaba.dubbo.remoting.transport.netty.NettyCodecAdapter$InternalDecoder.exceptionCaught(NettyCodecAdapter.java:165)
at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:432)
at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:52)
at org.jboss.netty.channel.Channels.fireChannelDisconnected(Channels.java:360)
at org.jboss.netty.channel.socket.nio.NioWorker.close(NioWorker.java:593)
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:356)
at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:280)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:200)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:714)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:949)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1360)
at com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler.caught(AllChannelHandler.java:65)
... 15 more
问题分析过程
1. 分析异常信息,发现无法创建新的线程;
2. 了解微服务部署架构,发现共六个微服务,都部署在一个Tomcat中;
3. 打开JDK自带的分析工具,jvisualvm.exe,该程序在JAVA_HOME\bin目录下,载入Tomcat查看线程情况,发现Tomcat的MaxThread设置在800;
4. 通过dubbo的status命令,发现服务的线程池配置为固定200个连接,6个服务需要1200个连接,超过了Tomcat的MaxThread,所以Tomcat无法创建新线程;
问题原因与解决方案
项目将Dubbo微服务打包成.war程序,放在Tomcat容器中,借助Tomcat启动微服务,使用Tomcat的JVM。由于放在该Tomcat中的微服务过多,Tomcat的配置满足不了微服务的需求,所以发生了该原因。
同样相似的问题有,在多个微服务中单独使用数据库线程池,连接同一个数据库,造成连接池溢出。
解决方法有几种:
- l 将Dubbo服务使用Dubbo推荐的打包方式,构建成独立的.jar程序,每个服务单独启动,独享JVM。
- l 修改Tomcat的MaxThread满足线程数量要求(不推荐,Tomcat线程数也不是无限的,而且基于操作系统,Window中一个进程可以开启大约2000个线程,Linux中默认一个进行只能开启1000个线程);
- l 修改Dubbo的配置,合理设置线程池的驻留线程数量;