从nacos客户端的TIME_WAIT说起

简介: 前段时间调研nacos,用来代替zookeeper当作dubbo的注册中心,使用的是nacos的1.1.4版本。还用了nacosSync,一款nacos提供的迁移工具,可将常见的注册中心上的服务同步到nacos上。这玩意很不好用,至少不是生产级别的工具。

问题起因


前段时间调研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引起了我的注意.


640.png


nacos的Java客户端使用rest的http接口来请求。这个bugfix中说道


dubbo 在使用nacos注册中心的时候,dubbo的消费端出现大量的TIME_WAIT状态的连接,占用大量的端口,每次请求/心跳都是新建连接,没有共享连接。从javadoc看,问题可能出在HttpURLConnection的使用上,每次请求都调用了disconnect,关闭了连接。


640.png


去nacosSync服务器(本质上是一个nacos客户端)上查看一下连接状态(现场没有保留,这是后来模拟的)


640.png


然后看了错误日志


java.net.ConnectException: Can't assign requested address (connect failed)


差不多确定这个bug导致了很严重的问题,很可能是服务经常掉线的罪魁祸首。


问题处理&分析


将这个issue的代码合并到调研版本,重新打包重启nacosSync,果然TIME_WAIT数量下去了,经过几天测试,nacos服务也不会再无故下线了。问题解决很简单,但是为什么会产生这种情况?看下修复代码


640.png


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三次握手


640.png


如图,tcp建立连接的三次握手过程如下:


  • (1)开始时A处于关闭,B处于LISTEN状态,A发起建立连接的请求,发送SYN=1的报文段,初始序列号seq=x,A进入SYN-SENT状态
  • (2)B收到请求报文后,同意建立连接,发送SYN=1,ACK=1的报文段,确认序列号为ack=x+1,同时B的初始序列号为seq=y,B进入SYN-RCVD状态
  • (3)当A收到B的确认后,也需要向B给出确认,ACK=1,seq=x+1,ack=y+1,此后A、B进入ESTABLISHED状态


然而tcp协议更需要考虑的是异常情况


  • (异常A)如果(1)中A发送报文时发生丢包导致B未收到,则A会重试,重试超时后,会进入CLOSED状态;
  • (异常B)如果(2)收到A的请求,但未回复或者或者回复报文丢失,对A来说就是(异常A),如果B回复的报文丢失,即A收不到确认报文,也不会发生(3),此时B也会重试,超时后关闭这个连接;
  • (异常C)A最后一个确认包丢失了,此时A已经进入ESTABLISHED状态,可以发送数据,B还是SYN-RCVD状态,此时如果B先收到A的数据包,则也会进入ESTABLISHED状态;如果A不发送最后一个确认包,也不发送数据,此时B处于“半连接”状态,会在重试几次(2)之后关闭连接,这就是“SYN FLOOD 攻击”。


tcp四次挥手


640.png


  • (1)开始A、B都处于ESTABLISHED状态,A主动关闭,发送FIN=1报文,seq=u,A进入FIN-WAIT-1状态;
  • (2)B收到关闭信号后,回复ACK=1,seq=v,ack=u+1,B进入CLOSE-WAIT状态,此时B还可以向A发送数据,A收到B的回复后进入FIN-WAIT-2状态;
  • (3)等B数据发送完毕后,向A发送可以关闭信号,FIN=1,ACK=1,seq=w,ack=u+1,B进入LAST-ACK状态;
  • (4)A收到B的关闭信号后回复确认,ACK=1,seq=u+1,ack=w+1,A进入TIME-WAIT状态,等待2MSL(即120秒)后进入CLOSED状态,B收到A的确认后进入CLOSED状态。


异常情况:


  • (异常A)A发起关闭信号进入FIN-WAIT-1,若B未回复,则会一直重试直到超时,超时后A直接关闭连接;
  • (异常B)B回复A后进入CLOSE-WAIT状态,但没有发送下一个FIN报文,则B一直处于CLOSE-WAIT状态;
  • (异常C)A收到B的ACK后进入FIN-WAIT-2状态,等待B的关闭,此时仍然可接收B的数据;理论上FIN-WAIT-2在未收到B的关闭请求前都是保持这个状态,但实际的实现却是有一个超时时间,linux默认是180秒,超时后直接关闭这个连接;
  • (异常D)B发送关闭连接报文FIN后进入LAST-ACK状态,但未收到回复,B会重复发送关闭请求,直到超时,超时后关闭该连接。


由tcp的三次握手与四次挥手能得出如下结论:


  • tcp之所以需要四次挥手是因为tcp连接是全双工,前两次挥手保证了A到B的关闭,后两次保证了B到A的关闭;
  • 在客户端设置 TIME_WAIT 是为了保证最后一个ACK能大概率送达B,如果不等待2MSL直接关闭连接,同时ACK也丢失,那么B再重发的关闭请求就无法处理,B大概率会停留在LAST-ACK状态;
  • 在没有攻击的情况下,容易出问题的是CLOSE-WAIT与TIME-WAIT状态;CLOSE-WAIT是服务端没有关闭连接,通常是代码中忘了关闭连接;TIME-WAIT出现则通常在客户端,客户端在短时间内发起了太多的连接,可以复用连接来解决该问题。
  • 如果出现其他中间状态较多的情况,可按上面的图进行分析,考虑是否存在攻击。


总结


  • 在处理请求的客户端时需要注意使用短链接会可能会造成TIME_WAIT过多的情况;
  • 在写代码的时候要注意可能会导致的异常情况,不使用的资源(包括但不限于连接)需要及时释放;
  • 对于开源产品的使用需要多看github上的issue,尽量提前预知可能的问题,在下一个版本发布时,需要关注修复的bug以及推出的新功能。


相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
Java Serverless Nacos
Serverless应用引擎问题之nacos客户端报错如何解决
在进行Serverless应用开发和部署时,开发者可能会遇到不同类型的报错信息;本合集着重收录了Serverless环境中常见的报错问题及其解决策略,以助于开发者迅速诊断和解决问题,保证服务的连续性和可用性。
365 1
|
缓存 前端开发 Java
nacos常见问题之开启鉴权后客户端报403升级版本如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
2574 0
|
3月前
|
网络协议 Shell PHP
简单的php版本nacos客户端
这是一个简单的 PHP 版本 Nacos 客户端,支持服务注册、配置发布、服务发现等功能。通过 Composer 安装,提供服务端与客户端示例代码,可快速集成至项目中。适用于基于 Nacos 的微服务架构开发,帮助实现服务治理与配置管理。
93 10
|
网络安全 Nacos
Nacos客户端配置错误检查
Nacos客户端配置错误检查
602 3
|
Java Nacos 开发工具
【Nacos】心跳断了怎么办?!8步排查法+实战代码,手把手教你解决Nacos客户端不发送心跳检测问题,让服务瞬间恢复活力!
【8月更文挑战第15天】Nacos是一款广受好评的微服务注册与配置中心。然而,“客户端不发送心跳检测”的问题时有发生,可能导致服务实例被视为离线。本文介绍如何排查此类问题:确认Nacos服务器地址配置正确;检查网络连通性;查看客户端日志;确保Nacos SDK版本兼容;调整心跳检测策略;验证服务实例注册状态;必要时重启应用;检查影响行为的环境变量。通过这些步骤,通常可定位并解决问题,保障服务稳定运行。
789 0
|
SpringCloudAlibaba Java Nacos
nacos源码分析-服务注册(客户端)
一直都想写SpringCloudAlibaba的源码分析,终于开始动手第一篇了,如果想要看懂Nacos源码至少要把《SpringBoot自动》配置看了,不然就是看天书。本篇文章呢带大家一起来看一下Nacos-Client 客户端服务注册这一部分的源码。
|
缓存 网络安全 Nacos
登录nacos客户端提示no message available
登录nacos客户端提示no message available
|
Kubernetes 关系型数据库 MySQL
nacos常见问题之客户端不发送心跳检测如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
652 2
|
安全 Nacos
在Nacos中,您可以通过配置服务注册IP白名单来限制只有特定网段的客户端才能进行服务注册
在Nacos中,您可以通过配置服务注册IP白名单来限制只有特定网段的客户端才能进行服务注册【1月更文挑战第18天】【1月更文挑战第87篇】
1369 4
|
Kubernetes 容灾 Java
nacos常见问题之客户端版本是2.2.1服务端是2.2.3启动报错如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
1374 0

热门文章

最新文章