У меня есть прокси-сервер socks5, написанный на golang. Демон прослушивает 10000 портов от 15000 до 25000, и это список прокси. Недавно мы начали тестировать его с некоторыми клиентами, и у нас получается около 500 оборотов в секунду на 5000 из этих портов. Я думаю, это не так много, но я сразу же укажу кучу проблем.
Сервер Ubuntu 18, 8 ядер, 32 ГБ ОЗУ, 1 ГБ сети. Я наблюдаю почти 800% CPU все время и постоянно растущее число состояний сокетов CLOSE_WAIT и TIME_WAIT. Я внимательно изучаю код около недели, но не вижу никаких проблем, все соединения закрываются везде.
pprof говорит, что это все о системных вызовах, точнее о чтении сокетов. ReadAtLeast здесь читает первые 3 байта запроса socks5, чтобы определить тип запроса.
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 от клиента.
В качестве временного решения я помещаю команду перезапуска в crontab каждые 15 минут, поэтому все соединения CLOSE_WAIT сбрасываются, а TIME_WAIT немного уменьшается, но это простои и т. Д.