nginx + Jetty: miles de conexiones atascadas en LAST_ACK

nginx + Jetty: miles de conexiones atascadas en LAST_ACK

Tengo una máquina FreeBSD con cárceles, dos en particular, una que ejecuta nginx y otra que ejecuta un programa Java que acepta solicitudes a través de Jetty (modo integrado).

Jetty recibe más de 500 solicitudes por segundo constantemente y últimamente ha habido un problema por el cual constantemente tengo más de 500 solicitudes por segundo.60.000conexiones en el estado LAST_ACK entre nginx y jetty.

Distribución de todas las conexiones (incluye algunos otros servicios, particularmente 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

Distribución de nginx -> conexiones de embarcadero

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

Preferiría que cada solicitud cierre completamente la conexión. Las solicitudes de los clientes tienen una diferencia de aproximadamente 10 minutos entre sí, por lo que las conexiones deben cerrarse.

Algunas de las conexiones,

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..
  • En el extremo de Jetty lo configuré maxIdleTimeen 2000; antes de esto, todas las conexiones estaban activadas, ESTABLISHEDpero ahora lo están.LAST_ACK
  • En el extremo de Jetty he puesto Connection: close(es decir response.setHeader(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE);)
  • Jetty nunca reporta muchas conexiones abiertas, siempre muy pocas.
  • PF/IPFW no se utiliza actualmente
  • nginx - reset_timedout_connectionestá activado

No puedo entender cómo hacer que nginx o jetty cierren la conexión por la fuerza. ¿Es esto simplemente algo que debe arreglarse en Jetty para que cierre completamente el socket una vez finalizada la solicitud?

Muchas gracias por adelantado

EDITAR:Olvidé mi configuración de nginx para la configuración del proxy.

    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;

EDITAR2:Obligar a Jetty a cerrar la conexión request.getConnection().getEndPoint().close()no hace nada; es obvio que la conexión SE ESTÁ cerrando (como está en LAST_ACK), pero ¿por qué no se supera esto? ¿Nginx mantiene la conexión abierta con el backend por algún motivo?

Respuesta1

Bueno, finalmente pude convencer a Jetty para que jugara bien.

Solo para resumir, así es como se ven mis conexiones ahora, en toda la máquina:

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

Y entre nginx y Jetty

1 FIN_WAIT_2
3 LISTEN
14 ESTABLISHED

Ya he estado cerrando toda la conexión y EndPoint(llamando close()a EndPointcerrar el subyacente SocketChannel) usando este método conveniente:

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();
}

(Solo envío una línea como máximo al cliente, por lo que no se necesita nada sofisticado)

Sin embargo, esto aún resultó en llenar todo el servidor con LAST_ACK... Lo que hizo que finalmente desaparecieran fue habilitar SO_LINGER(y hacer que cerrara el socket inmediatamente, sin tiempo de espera)

connector.setSoLingerTime(0);

información relacionada