【发布时间】:2019-10-30 18:49:44
【问题描述】:
我有用 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 减少了一点,但这是停机时间等。
【问题讨论】:
-
CLOSE_WAIT 表示您没有在应该关闭套接字时关闭套接字,即当您读取 EOS 时。 TIME_WAIT 是正常的,但您可以通过不关闭直到从对等方获得 EOS 来减少它们。