У меня есть машина 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..
maxIdleTime
до 2000 года - до этого все подключения были в ESTABLISHED
но они сейчас LAST_ACK
Connection: close
(т.е. response.setHeader(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE);
)reset_timedout_connection
наЯ не могу понять, как заставить 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);