我在golang上编写了socks5代理服务器。守护程序正在侦听从15000到25000的10000个端口,因此这是一个代理列表。最近,我们开始在一些客户端上对其进行测试,最终在其中5000个端口上获得了约500 rps。这不是我想的那么多,但我立即指出了很多问题。
服务器为Ubuntu 18、8核,32G RAM,1Gb网络。我一直观察到几乎800%的CPU,并且CLOSE_WAIT和TIME_WAIT套接字状态的数量不断增加。我花了大约一周的时间仔细研究代码,但没有指出任何问题,所有连接都在各处关闭。
pprof表示,这全都与系统调用有关,更确切地说是与套接字读取有关。 ReadAtLeast正在读取socks5请求的前3个字节,以确定请求的类型。
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则有所减少,但这是停机时间。
答案 0 :(得分:-1)
您可以尝试:
conn, ok = conn.(*net.TCPConn)
if ok {
conn.SetLinger(0)
}
使用此选项,内核将更快地关闭TIME_WAIT和CLOSE_WAIT(终止状态)套接字。
注释: