由于CLOSE_WAIT和TIME_WAIT套接字数量增加,代理服务器不稳定

时间:2019-06-17 07:45:50

标签: go tcp proxy

我在golang上编写了socks5代理服务器。守护程序正在侦听从15000到25000的10000个端口,因此这是一个代理列表。最近,我们开始在一些客户端上对其进行测试,最终在其中5000个端口上获得了约500 rps。这不是我想的那么多,但我立即指出了很多问题。

服务器为Ubuntu 18、8核,32G RAM,1Gb网络。我一直观察到几乎800%的CPU,并且CLOSE_WAIT和TIME_WAIT套接字状态的数量不断增加。我花了大约一周的时间仔细研究代码,但没有指出任何问题,所有连接都在各处关闭。

pprof表示,这全都与系统调用有关,更确切地说是与套接字读取有关。 ReadAtLeast正在读取socks5请求的前3个字节,以确定请求的类型。

enter image description here

func (s *Server) Serve(conn net.Conn) error {
    defer conn.Close() // seems doesn't work too

    _ = conn.SetDeadline(time.Now().Add(time.Second * 30)) // doesn't work

    request, err := NewRequest(conn)
    if err != nil {
        return err
    }

    // Process the client request
    return s.handleRequest(request, conn)
}

func NewRequest(bufConn io.Reader) (*Request, error) {
    header := []byte{0, 0, 0}
    if _, err := io.ReadAtLeast(bufConn, header, 3); err != nil {
        return nil, fmt.Errorf("Failed to get command version: %v", err)
    }

    // ...
}

net.ipv4.tcp_fin_timeout = 25,所以2MSL是50秒,但是似乎套接字没有足够的时间关闭,因为新的套接字会很快进入。这大约是TIME_WAIT。我不知道CLOSE_WAIT有什么问题。我确实关闭了连接,但似乎没有从客户端获得FIN_ACK。

作为一个临时解决方案,我每隔15分钟将重新启动命令放在crontab中,因此所有CLOSE_WAIT连接均被断开,而TIME_WAIT则有所减少,但这是停机时间。

enter image description here

1 个答案:

答案 0 :(得分:-1)

您可以尝试:

conn, ok = conn.(*net.TCPConn)
if ok {
     conn.SetLinger(0)
}

使用此选项,内核将更快地关闭TIME_WAIT和CLOSE_WAIT(终止状态)套接字。

注释:

  • TIME_WAIT:您的服务器启动了tcp终止,TIME_WAIT是该tcp conn在服务器上的最后状态
  • CLOSE_WAIT:客户端启动了tcp终止,您的服务器正在等待来自客户端的FIN ACK