Нестабильный прокси-сервер из-за растущих сокетов CLOSE_WAIT и TIME_WAIT - PullRequest
0 голосов
/ 17 июня 2019

У меня есть прокси-сервер socks5, написанный на golang. Демон прослушивает 10000 портов от 15000 до 25000, и это список прокси. Недавно мы начали тестировать его с некоторыми клиентами, и у нас получается около 500 оборотов в секунду на 5000 из этих портов. Я думаю, это не так много, но я сразу же укажу кучу проблем.

Сервер Ubuntu 18, 8 ядер, 32 ГБ ОЗУ, 1 ГБ сети. Я наблюдаю почти 800% CPU все время и постоянно растущее число состояний сокетов CLOSE_WAIT и TIME_WAIT. Я внимательно изучаю код около недели, но не вижу никаких проблем, все соединения закрываются везде.

pprof говорит, что это все о системных вызовах, точнее о чтении сокетов. ReadAtLeast здесь читает первые 3 байта запроса socks5, чтобы определить тип запроса.

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 от клиента.

В качестве временного решения я помещаю команду перезапуска в crontab каждые 15 минут, поэтому все соединения CLOSE_WAIT сбрасываются, а TIME_WAIT немного уменьшается, но это простои и т. Д.

enter image description here

1 Ответ

0 голосов
/ 18 июня 2019

вы можете попробовать:

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

с этой опцией ядро ​​закроет сокеты TIME_WAIT и CLOSE_WAIT (завершающие состояния) быстрее.

примечания:

  • TIME_WAIT: ваш сервер инициировал tcp-завершение, TIME_WAIT - это последнее состояние этого tcp-соединения на вашем сервере
  • CLOSE_WAIT: клиент-инициированное tcp-завершение, ваш сервер ожидает FIN ACK от клиента
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...