一、发现问题
先看看问题表象:
1、 服务消费者端应用本地保存注册列表异常,报Too many open files
点击(此处)折叠或打开
-
[DubboSaveRegistryCache-thread-1]14:37:30.714 WARN c.a.dubbo.registry.zookeeper.ZookeeperRegistry-[DUBBO]Failed tosaveregistrystorefile,cause:/data/crm/crmsca/.dubbo/dubbo-registry-132.121.91.184.cache.lock(Too manyopenfiles),dubboversion:2.5.3,currenthost:132.121.91.71
-
java.io.FileNotFoundException:/data/crm/crmsca/.dubbo/dubbo-registry-132.121.91.184.cache.lock(Too manyopenfiles)
-
atjava.io.RandomAccessFile.open(NativeMethod)~[na:1.6.0_35]
-
atjava.io.RandomAccessFile.<init>(RandomAccessFile.java:216)~[na:1.6.0_35]
-
at com.alibaba.dubbo.registry.support.AbstractRegistry.doSaveProperties(AbstractRegistry.java:187)~[dubbo-2.5.3.jar:2.5.3]
-
at com.alibaba.dubbo.registry.support.AbstractRegistry$SaveProperties.run(AbstractRegistry.java:150)[dubbo-2.5.3.jar:2.5.3]
-
atjava.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)[na:1.6.0_35]
-
atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)[na:1.6.0_35]
-
atjava.lang.Thread.run(Thread.java:662)[na:1.6.0_35]
-
[DubboSaveRegistryCache-thread-1]14:37:30.715 WARN c.a.dubbo.registry.zookeeper.ZookeeperRegistry-[DUBBO]Failed toloadregistrystorefile,cause:/data/crm/crmsca/.dubbo/dubbo-registry-132.121.91.184.cache(Too manyopenfiles),dubboversion:2.5.3,currenthost:132.121.91.71
2、 消费者经常出现超时调用的问题
点击(此处)折叠或打开
-
[DubboSaveRegistryCache-thread-1]14:37:30.714 WARN c.a.dubbo.registry.zookeeper.ZookeeperRegistry-[DUBBO]Failed tosaveregistrystorefile,cause:/data/crm/crmsca/.dubbo/dubbo-registry-132.121.91.184.cache.lock(Too manyopenfiles),dubboversion:2.5.3,currenthost:132.121.91.71
-
java.io.FileNotFoundException:/data/crm/crmsca/.dubbo/dubbo-registry-132.121.91.184.cache.lock(Too manyopenfiles)
-
atjava.io.RandomAccessFile.open(NativeMethod)~[na:1.6.0_35]
-
atjava.io.RandomAccessFile.<init>(RandomAccessFile.java:216)~[na:1.6.0_35]
-
at com.alibaba.dubbo.registry.support.AbstractRegistry.doSaveProperties(AbstractRegistry.java:187)~[dubbo-2.5.3.jar:2.5.3]
-
at com.alibaba.dubbo.registry.support.AbstractRegistry$SaveProperties.run(AbstractRegistry.java:150)[dubbo-2.5.3.jar:2.5.3]
-
atjava.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)[na:1.6.0_35]
-
atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)[na:1.6.0_35]
-
atjava.lang.Thread.run(Thread.java:662)[na:1.6.0_35]
-
[DubboSaveRegistryCache-thread-1]14:37:30.715 WARN c.a.dubbo.registry.zookeeper.ZookeeperRegistry-[DUBBO]Failed toloadregistrystorefile,cause:/data/crm/crmsca/.dubbo/dubbo-registry-132.121.91.184.cache(Too manyopenfiles),dubboversion:2.5.3,currenthost:132.121.91.71
3、 服务消费者端应用出现socket连不上
点击(此处)折叠或打开
-
[DubboClientReconnectTimer-thread-1]09:57:59.419ERRORc.a.dubbo.remoting.transport.AbstractClient-[DUBBO]clientreconnectto 13
-
2.121.91.179:20883finderror.url:dubbo://132.121.91.179:20883/com.eshore.crm.api.intfmgr.acc.IAccServiceanyhost=true&applicatio
-
n=crmsca-service&architecture=service&check=false&cityids=N/A&codec=dubbo&connections=100&default.async=false&default.connections=15
-
0&default.proxy=crmProxyFactory&default.retries=0&default.serialization=hessian2&default.service.filter=dstFingerFilter,-default&def
-
ault.timeout=60000&default.token=false&dubbo=2.5.3&dynamic=true&heartbeat=60000&interface=com.eshore.crm.api.intfmgr.acc.IAccService
-
&ip=132.121.91.70&logger=crm4j&mac=E2:2A:30:C3:52:B8&methods=qryChannel,verifySmsRandomCode,figureVerify,getSmsRandomCode,getReportS
-
tate,queryUnifyStaffInfo&monitor=dubbo%3A%2F%2F132.121.91.184%3A7070%3Fdefault%3Dtrue%26dubbo%3D2.5.3%26interface%3Dcom.alibaba.dubb
-
o.monitor.MonitorService%26pid%3D16633%26timestamp%3D1442231057363&pid=16633&port=8001&proxy=crmProxyFactory&reference.filter=srcFin
-
gerFilter,monitor,-default&retries=0&revision=1.0&serialization=hessian2&side=consumer&timeout=60000×tamp=1442231057352&token=f
-
alse,dubboversion:2.5.3,currenthost:132.121.91.70
-
com.alibaba.dubbo.remoting.RemotingException:Failedconnecttoserver/132.121.91.179:20883fromNettyClient 132.121.91.70 using dubboversion2.5.3,cause:Failed toopenasocket.
-
at com.alibaba.dubbo.remoting.transport.AbstractClient.connect(AbstractClient.java:297)~[dubbo-2.5.3.jar:2.5.3]
从上面的问题看出,问题在于 Too many open files和 Failed to open a socket .
二、分析问题
1、分析tcp连接
首先从表象来看,too many open files这个问题网上有很多答案,就是文件句柄数超过了系统设置,系统设置为65535。而linux文件句柄是包含了文件的读写和tcp连接。
可参考:http://langyu.iteye.com/blog/763247
于是,我们用netstat -an | grep port来看一下端口情况:
点击(此处)折叠或打开
-
[crmsca@server-91-70~]$netstat-an|grep 20895|wc-l
-
71854
可以看到,dubbo服务有7W多个连接。而系统设置ulimit -n 的值 65535,所以是有可能把连接爆掉的。
这时,很容易怀疑的是连接状态是否正常,是否很多CLOSE_WAIT或TIME_WAIT。查看了都是ESTABLISHED状态。
这就奇怪了,几万个连接都是正常的,也不释放。一般http短连接,一个WEB域只有10个以内的连接,200个左右线程处理。
2、分析dubbo的NIO机制
先判断7W个连接都是dubbo的消费者到dubbo提供者之间的。如下图第4
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Svpfr14f-1662086029274)(http://blog.itpub.net/attachment/201509/16/11627468_1442380178cn3R.jpg)]
想到dubbo的连接机制与一般http短连接服务不一样,dubbo是NIO的机制。所以研究nio的机制。
关于nio的Reactor模式参考:http://ryanflyer.iteye.com/blog/1672876
本来认为可能是因为后端服务慢,导致前端请求阻塞。分析Rector后发现,只有一条长连接。其它都是线程池处理。为什么连接数会这么多呢?原来dubbo协议是单一长连接的协议,是不会释放的。参考:http://blog.csdn.net/freebird_lb/article/details/7303235
dubbo可以支持dubbo、http、rmi等多种协议,而Dubbo缺省协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D7BCLC9F-1662086029275)(http://blog.itpub.net/attachment/201509/16/11627468_1442380084wxaA.jpg)]
3、分析dubbo的长连接机制
参考网上的dubbo问题: http://www.52ml.net/7601.html ,和我们生产现象也不一样。
查看配置发现dubbo配置每个服务提供者都是配置连接数为100或150的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aWfPekLV-1662086029276)(http://blog.itpub.net/attachment/201509/16/11627468_1442380412DTn5.jpg)]
而提供者有100个,加上dubbo的集群,就有200个提供者。消费者是比提供者多的,而且还会增多。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cuhgSNEX-1662086029276)(http://blog.itpub.net/attachment/201509/16/11627468_1442380467Pv6P.jpg)]
而且生产不是延迟加载,那么有一个消费者加进来。就会增加100个连接。这样累加起来,就有几万个了。
因此需要验证以下想法:
1、减少服务连接,是否可以减少TCP连接数。
2、连接数是否会由于消费者的增加而成倍增加。
通过验证发现,1、TCP连接数会减少 2、会成倍增加
而连接与线程数不是一个概念。所以连接数10以下就可以,线程数一般100到300,由线程池管理。
点击(此处)折叠或打开
-
缺省协议,使用基于mina1.1.7+hessian3.2.1的tbremoting交互。
-
连接个数:单连接
-
连接方式:长连接
-
传输协议:TCP
-
传输方式:NIO异步传输
-
序列化:Hessian二进制序列化
-
适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串。
-
适用场景:常规远程服务方法调用
-
为什么要消费者比提供者个数多:
-
因dubbo协议采用单一长连接,
-
假设网络为千兆网卡(1024Mbit=128MByte),
-
根据测试经验数据每条连接最多只能压满7MByte(不同的环境可能不一样,供参考),
-
理论上1个服务提供者需要20个服务消费者才能压满网卡。
参考dubbo官网资料: http://dubbo.io/User+Guide-zh.htm
三、解决问题。
问题原因:
1、官网建议在Provider上尽量多配置Consumer端属性,而生产上设置是没有这样做的,导致客户端的配置以服务提供者为准 。
2、Provider上配置 合理的Provider端属性。而生产上也没有这样做,没有对总的dubbo做连接数限制。所以导致连接数爆了。
3、连接数设置不合理,设置过大 。一个连接可以同时处理10个、100个并发都是没有问题的。
4、未设置延迟加载,导致tcp长连接浪费。
解决方法:
1、先减少连接数为10观察,后续一般服务 减 少 到 2 ,大并发服务设置为10。
2、使用延迟加载配置。
四、总结
1、连接数和并发数、线程数不是一个概念。连接数是与网络连接有关的。一个连接数可以支持70Mbype的网络流量。
多个并发请求是在一个tcp连接上传输的。传输到达dubbo端后,dubbo会把tcp连接上的请求分配给线程池中的线程处理。
2、长连接是一直占用的网络连接,线程会超时,而长连接不会断开。
3、nio rector机制通过长连接来减少tcp握手和挥手的开销。通过事件通知来实现非阻塞式传输,因些阻塞不会传递。
。