nginx + Jetty - milhares de conexões presas em LAST_ACK

2

Eu tenho uma máquina FreeBSD com jails - duas em particular, uma que executa nginx e outra que executa um programa Java que aceita solicitações via Jetty (modo embutido)

O Jetty recebe mais de 500 solicitações / seg constantemente e tem havido um problema ultimamente em que constantemente tenho mais de 60.000 conexões no estado LAST_ACK entre o nginx e o Jetty.

Distribuição de todas as conexões (inclui alguns outros serviços, 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

Distribuição de nginx - > conexões de molhe

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

Eu preferiria que todas as solicitações fechassem totalmente a conexão. Os pedidos de clientes estão separados por cerca de 10 minutos, portanto, as conexões devem ser fechadas.

Algumas das conexões,

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..
  • No final do Jetty, defini maxIdleTime para 2000 - antes disso, todas as conexões estavam em ESTABLISHED , mas agora elas são LAST_ACK
  • No final do Jetty, defini Connection: close (ou seja, response.setHeader(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE); )
  • O Jetty nunca relata muitas conexões abertas - sempre muito poucas.
  • PF / IPFW não está sendo usado no momento
  • nginx - reset_timedout_connection está em

Não consigo descobrir como obter o nginx ou o jetty para fechar a conexão forçadamente. Isso é algo que simplesmente precisa ser corrigido no Jetty para que ele feche completamente o soquete após a conclusão da solicitação?

Agradecemos antecipadamente

EDIT: esqueci minha configuração nginx para a configuração do 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;

EDIT2: Forçar o Jetty a fechar a conexão via request.getConnection().getEndPoint().close() não faz nada - é óbvio que a conexão está sendo fechada (como em LAST_ACK ), mas por que não está passando ? O Nginx está mantendo a conexão aberta para o backend por algum motivo?

    
por virulence 27.08.2012 / 20:56

1 resposta

0

OK, eu finalmente consegui convencer o Jetty a jogar bem.

Só para recapitular, veja como minhas conexões estão agora, em toda a máquina:

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

E entre o nginx e o Jetty

1 FIN_WAIT_2
3 LISTEN
14 ESTABLISHED

Eu já fechei a conexão inteira e EndPoint (chamando close() no EndPoint fecha o SocketChannel subjacente) usando este método de conveniência:

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

(Eu só envio no máximo uma linha para o cliente, então nada é necessário)

No entanto, isso ainda resultou no preenchimento de todo o servidor com LAST_ACK ... O que fez estes últimos desaparecerem foi habilitar SO_LINGER (e fazê-lo fechar o socket imediatamente, sem tempo limite)

connector.setSoLingerTime(0);
    
por 28.08.2012 / 23:15