记一次CLOSE_WAIT
背景:
预发布环境在拉取代码时,页面报Curl Failed :Connection reset by peer ,php后台报connection timeout是php代码部分调用拉取接口时报出来的,通过netstat查看该接口目前的tcp连接状态
可以看到服务端的连接一直处于close_wait状态,连接一直没释放掉,由于该接口是单线程的,导致新的请求一直阻塞(从第二列可以看到),用户发现一直响应不了就会频繁刷新网页,导致连接数剧增
第二列和第三列的含义如下:
第二列表示网络接收队列(recv-Q)
表示收到的数据已经在本地缓冲区,但是还有多少没有被对端服务取走,
如果接收队列Recv-Q一直处于阻塞状态,可能是遭受了拒绝服务 denial-of-service 攻击,说白了就是产生了很多连接导致服务端处理不过来了。
第三列表示网路发送队列(send-Q)
对方没有收到的数据或者说没有Ack的,还是本地缓冲区.
如果发送队列Send-Q不能很快的清零,可能是有应用向外发送数据包过快,或者是对方接收数据包过慢。
这个问题可以通过一下代码复现
服务端
package main
import (
"net"
"time"
)
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:8888")
if err != nil {
panic(err)
}
defer listen.Close()
for {
conn, err := listen.Accept()
if err != nil {
panic(err)
}
time.Sleep(20*time.Second)
conn.Close()
}
}
客户端
package main
import (
"log"
"net"
"time"
)
func main(){
conn, err := net.Dial("tcp", "127.0.0.1:8888")
if err != nil {
log.Println("dial error:", err)
return
}
defer conn.Close()
time.Sleep(1*time.Second)
buf := make([]byte, 1024)
n, err := conn.Write(buf)
log.Println(n, err)
}
客户端和服务端建立连接后,发送1024字节的数据包,服务端收到请求后,一直不处理数据,直到20s后退出,此时通过netstat查看
可以看到网络接收队列(recv-Q)里的数据一直阻塞没有被服务端处理。
解决思路
将服务改为多线程,加快服务端的处理速度。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App