nginx + Jetty - тысячи соединений застряли в LAST_ACK
У меня есть машина с FreeBSD с джейлами - две, в частности, одна, на которой работает nginx, а другая на Java-программе, которая принимает запросы через Jetty (встроенный режим).
Jetty получает свыше 500 запросов в секунду постоянно, и в последнее время возникла проблема, из-за которой у меня постоянно будет более 60000 соединений в состоянии LAST_ACK между nginx и jetty.
Распределение всех подключений (включает некоторые другие сервисы, в частности 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);
) - Jetty никогда не сообщает о многих открытых соединениях - всегда очень мало.
- PF / IPFW в настоящее время не используется
- nginx -
reset_timedout_connection
находится на
Я не могу понять, как заставить nginx или jetty принудительно закрыть соединение, это просто то, что нужно исправить в 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;
EDIT2: Принудительно Jetty, чтобы закрыть соединение через request.getConnection().getEndPoint().close()
ничего не делает - очевидно, что соединение закрыто (как в LAST_ACK
) но почему бы не пройти через это? Сохраняет ли Nginx соединение открытым для бэкэнда по какой-то причине?
1 ответ
Хорошо, я наконец-то смог убедить Джетти хорошо играть.
Вкратце, вот как выглядят мои соединения для всей машины:
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);