记一次close_wait

背景:

预发布环境在拉取代码时,页面报Curl Failed :Connection reset by peer ,php后台报connection timeoutphp代码部分调用拉取接口时报出来的,通过netstat查看该接口目前的tcp连接状态

 

记一次close_wait

 

 

 

可以看到服务端的连接一直处于close_wait状态,连接一直没释放掉,由于该接口是单线程的,导致新的请求一直阻塞(从第二列可以看到),用户发现一直响应不了就会频繁刷新网页,导致连接数剧增

第二列和第三列的意思如下:

 

第二列表示网络接收队列(recv-Q)

表示收到的数据已经在本地接收缓冲,但是还有多少没有被进程取走,recv()
如果接收队列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可以看到

 

 

记一次close_wait

 

 

网络接收队列(recv-Q)里的数据一直阻塞没有被服务端处理。

 

 

解决思路

 将服务改为多线程,加快服务端的处理速度

 

记一次close_wait

上一篇:微信小程序支付、退款


下一篇:答题小程序考试防作弊技术方案简析