【tcp】大量的close_wait,怎么排查?
TCP的close_wait在哪端,如果我们场景中出现了大量的close_wait,你觉得要怎么排查?
CLOSE_WAIT 状态是「被动关闭方」才会有的状态,而且如果「被动关闭方」没有调用 close 函数关闭连接,那么就无法发出 FIN 报文,从而无法使得 CLOSE_WAIT 状态的连接转变为 LAST_ACK 状态。
所以,当服务端出现大量 CLOSE_WAIT 状态的连接的时候,说明服务端的程序没有调用 close 函数关闭连接。
那什么情况会导致服务端的程序没有调用 close 函数关闭连接?这时候通常需要排查代码。
我们先来分析一个普通的 TCP 服务端的流程:
- 创建服务端 socket,bind 绑定端口、listen 监听端口
- 将服务端 socket 注册到 epoll
- epoll_wait 等待连接到来,连接到来时,调用 accpet 获取已连接的 socket
- 将已连接的 socket 注册到 epoll
- epoll_wait 等待事件发生
- 对方连接关闭时,我方调用 close
可能导致服务端没有调用 close 函数的原因,如下。
第一个原因:第 2 步没有做,没有将服务端 socket 注册到 epoll,这样有新连接到来时,服务端没办法感知这个事件,也就无法获取到已连接的 socket,那服务端自然就没机会对 socket 调用 close 函数了。
不过这种原因发生的概率比较小,这种属于明显的代码逻辑 bug,在前期 read view 阶段就能发现的了。
第二个原因:第 3 步没有做,有新连接到来时没有调用 accpet 获取该连接的 socket,导致当有大量的客户端主动断开了连接,而服务端没机会对这些 socket 调用 close 函数,从而导致服务端出现大量 CLOSE_WAIT 状态的连接。
发生这种情况可能是因为服务端在执行 accpet 函数之前,代码卡在某一个逻辑或者提前抛出了异常。
第三个原因:第 4 步没有做,通过 accpet 获取已连接的 socket 后,没有将其注册到 epoll,导致后续收到 FIN 报文的时候,服务端没办法感知这个事件,那服务端就没机会调用 close 函数了。
发生这种情况可能是因为服务端在将已连接的 socket 注册到 epoll 之前,代码卡在某一个逻辑或者提前抛出了异常。之前看到过别人解决 close_wait 问题的实践文章,感兴趣的可以看看:
一次 Netty 代码不健壮导致的大量 CLOSE_WAIT 连接原因分析
https://blog.csdn.net/m0_71777195/article/details/128093553
第四个原因:第 6 步没有做,当发现客户端关闭连接后,服务端没有执行 close 函数,可能是因为代码漏处理,或者是在执行 close 函数之前,代码卡在某一个逻辑,比如发生死锁等等。
可以发现,当服务端出现大量 CLOSE_WAIT 状态的连接的时候,通常都是代码的问题,这时候我们需要针对具体的代码一步一步的进行排查和定位,主要分析的方向就是服务端为什么没有调用 close。
不同地区的用户的请求怎么打到附近的地区呢?
CDN 将内容资源分发到位于多个地理位置机房中的服务器上,这样我们在访问内容资源的时候,不用访问源服务器。而是直接访问离我们最近的 CDN 节点 ,这样一来就省去了长途跋涉的时间成本,从而实现了网络加速。
找到离用户最近的 CDN 节点是由 CDN 的全局负载均衡器(Global Sever Load Balance,GSLB)负责的。
那 GSLB 是在什么时候起作用的呢?在回答这个问题前,我们先来看看在没有 CDN 的情况下,访问域名时发生的事情。
在没有 CDN 的情况下,当我们访问域名时,DNS 服务器最终会返回源服务器的地址。
比如,当我们在浏览器输入 www.xiaolin.com 域名后,在本地 host 文件找不到域名时,客户端就会访问本地 DNS 服务器。
image.png这时候:
如果本地 DNS 服务器有缓存该网站的地址,则直接返回网站的地址;
如果没有就通过递归查询的方式,先请求根 DNS,根 DNS 返回顶级 DNS(.com)的地址;再请求 .com 顶级 DNS 得到 xiaolin.com 的域名服务器地址,再从 xiaolin.com 的域名服务器中查询到 www.xiaolin.com 对应的 IP 地址,然后返回这个 IP 地址,同时本地 DNS 缓存该 IP 地址,这样下一次的解析同一个域名就不需要做 DNS 的迭代查询了。
但加入 CDN 后就不一样了。
会在 xiaolin.com 这个 DNS 服务器上,设置一个 CNAME 别名,指向另外一个域名 www.xiaolin.cdn.com,返回给本地 DNS 服务器。
接着继续解析该域名,这个时候访问的就是 xiaolin.cdn.com 这台 CDN 专用的 DNS 服务器,在这个服务器上,又会设置一个 CNAME,指向另外一个域名,这次指向的就是 CDN 的 GSLB。
接着,本地 DNS 服务器去请求 CDN 的 GSLB 的域名,GSLB 就会为用户选择一台合适的 CDN 节点提供服务,选择的依据主要有以下几点:
看用户的 IP 地址,查表得知地理位置,找相对最近的 CDN 节点;
看用户所在的运营商网络,找相同网络的 CDN 节点;
看用户请求 URL,判断哪一台服务器上有用户所请求的资源;
查询 CDN 节点的负载情况,找负载较轻的节点;
GSLB 会基于以上的条件进行综合分析后,找出一台最合适的 CDN 节点,并返回该 CDN 节点的 IP 地址给本地 DNS 服务器,然后本地 DNS 服务器缓存该 IP 地址,并将 IP 返回给客户端,客户端去访问这个 CDN 节点,下载资源。