Назад | Перейти на главную страницу

nginx + Jetty - тысячи подключений застряли в LAST_ACK

У меня есть машина FreeBSD с тюрьмами - в частности, две, одна из которых запускает nginx, а другая - программу Java, которая принимает запросы через Jetty (встроенный режим).

Jetty постоянно получает более 500 запросов в секунду, и в последнее время возникла проблема, из-за которой у меня постоянно 60 000 соединения в состоянии LAST_ACK между nginx и причалом.

Распределение всех подключений (включая некоторые другие сервисы, в частности php-fpm)

root@host:/root # netstat -an > conns.txt
root@host:/root # cat conns.txt | awk '{print $6}' | sort | uniq -c | sort -n
18 LISTEN
112 CLOSING
485 ESTABLISHED
650 FIN_WAIT_2
1425 FIN_WAIT_1
3301 TIME_WAIT
64215 LAST_ACK

Распространение nginx -> причалы

root@host:/root # cat conns.txt | grep '10.10.1.57' | awk '{print $6}' | sort | uniq -c | sort -n
1 
3 CLOSE_WAIT
3 LISTEN
18 FIN_WAIT_2
125 ESTABLISHED
64193 LAST_ACK

Я бы предпочел, чтобы каждый запрос полностью закрывал соединение. Запросы клиентов отделяются друг от друга примерно на 10 минут, поэтому соединения должны быть закрыты.

Некоторые связи,

tcp4       0      0 10.10.1.50.46809       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46805       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46797       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46794       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46790       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46789       10.10.1.57.9050        LAST_ACK
tcp4       0      0 10.10.1.50.46771       10.10.1.57.9050        LAST_ACK
etc..

Я не могу понять, как заставить nginx или причал принудительно закрыть соединение, это просто что-то, что нужно исправить в Jetty, чтобы он полностью закрыл сокет после завершения запроса?

Заранее большое спасибо

РЕДАКТИРОВАТЬ: забыл мою конфигурацию nginx для настройки прокси -

    proxy_pass              http://10.10.1.57:9050;
    proxy_set_header        HTTP_X_GEOIP $http_x_geoip;
    proxy_set_header        GEOIP_COUNTRY_CODE $geoip_country_code;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        Host $http_host;
    proxy_set_header        Connection "";
    proxy_http_version      1.1;

РЕДАКТИРОВАТЬ2: Заставить Jetty закрыть соединение через request.getConnection().getEndPoint().close() ничего не делает - очевидно, что соединение закрывается (как в LAST_ACK) но почему это не проходит? Nginx по какой-то причине поддерживает соединение с серверной частью открытым?

Ладно, наконец-то я смог убедить Джетти играть хорошо.

Напомним, как сейчас выглядят мои соединения в масштабе всей машины:

24 LAST_ACK
36 CLOSING
117 FIN_WAIT_2
175 ESTABLISHED
351 FIN_WAIT_1
4725 TIME_WAIT

И между nginx и Jetty

1 FIN_WAIT_2
3 LISTEN
14 ESTABLISHED

Я уже закрыл все соединение и EndPoint (звонит close() на EndPoint закрывает базовый SocketChannel) с помощью этого удобного метода:

private void finishRequest(String message, Request baseRequest, HttpServletResponse response) throws IOException {
    ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(1500);
    writer.write(message);
    writer.flush();

    // set the content length
    response.setContentLength(writer.size());

    // write the response
    OutputStream outputStream = response.getOutputStream();
    writer.writeTo(outputStream);

    // close the streams
    outputStream.close();
    writer.close();
    baseRequest.getConnection().getEndPoint().close();
}

(Я отправляю клиенту максимум одну строку, поэтому ничего особенного не требуется)

Однако это все равно привело к заполнению всего сервера LAST_ACK ... Что заставило их окончательно исчезнуть, так это включение SO_LINGER (и заставляя его немедленно принудительно закрыть сокет, без тайм-аута)

connector.setSoLingerTime(0);