前段时间调研nacos,用来代替zookeeper当作dubbo的注册中心,使用的是nacos的1.1.4版本。还用了nacosSync,一款nacos提供的迁移工具,可将常见的注册中心上的服务同步到nacos上。这玩意很不好用,至少不是生产级别的工具。但这与本文无关,后面会专门写一篇文章来介绍这个同步工具的优缺点,以及生产级别还需要做哪些改造。开始测试时,总有服务莫名奇妙的下线了,一直找不到原因。后来在调研的过程中,nacos发布了1.2.0-beta.0版本,于是去github上看了1.2.0-beat.0的release note。把修复的bug一个一个去review,重要的都merge到调研版本上,其中有一个bugfix引起了我的注意。
nacos的Java客户端使用rest的http接口来请求。这个bugfix中说道
dubbo 在使用nacos注册中心的时候,dubbo的消费端出现大量的TIME_WAIT状态的连接,占用大量的端口,每次请求/心跳都是新建连接,没有共享连接。从javadoc看,问题可能出在HttpURLConnection的使用上,每次请求都调用了disconnect,关闭了连接。
去nacosSync服务器(本质上是一个nacos客户端)上查看一下连接状态(现场没有保留,这是后来模拟的)
然后看了错误日志
java.net.ConnectException: Can't assign requested address (connect failed)
差不多确定这个bug导致了很严重的问题,很可能是服务经常掉线的罪魁祸首。
将这个issue的代码合并到调研版本,重新打包重启nacosSync,果然TIME_WAIT数量下去了,经过几天测试,nacos服务也不会再无故下线了。问题解决很简单,但是为什么会产生这种情况?看下修复代码
Java Doc上这样说
Each HttpURLConnection instance is used to make a single request but the underlying network connection to the HTTP server may be transparently shared by other instances. Calling the close() methods on the InputStream or OutputStream of an HttpURLConnection after a request may free network resources associated with this instance but has no effect on any shared persistent connection. Calling the disconnect() method may close the underlying socket if a persistent connection is otherwise idle at that time.
调用 disconnect() 会关闭连接,关闭连接会导致 TIME_WAIT 状态的连接增多。看来需要复习一下tcp的基础知识,接下来介绍 tcp 建立连接的三次握手与断开连接的四次挥手,以下内容主要来自对谢希仁著的《计算机网络》(第7版)与网络上文章的理解。
如图,tcp建立连接的三次握手过程如下:
然而tcp协议更需要考虑的是异常情况
异常情况:
由tcp的三次握手与四次挥手能得出如下结论:
在处理请求的客户端时需要注意使用短链接会可能会造成TIME_WAIT过多的情况;
在写代码的时候要注意可能会导致的异常情况,不使用的资源(包括但不限于连接)需要及时释放;
对于开源产品的使用需要多看github上的issue,尽量提前预知可能的问题,在下一个版本发布时,需要关注修复的bug以及推出的新功能。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8