Eu tenho uma máquina FreeBSD com jails - duas em particular, uma que roda nginx e outra que roda um programa Java que aceita requisições via Jetty (modo embarcado)
Jetty recebe mais de 500 solicitações/seg constantemente e ultimamente tem havido um problema em que terei constantemente mais60.000conexões no estado LAST_ACK entre nginx e 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 cais
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
Prefiro que cada solicitação feche totalmente a conexão. As solicitações dos clientes estão separadas 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, configurei
maxIdleTime
para 2.000 - antes disso, todas as conexões estavam instaladas,ESTABLISHED
mas agora estãoLAST_ACK
- No final do Jetty eu configurei
Connection: close
(ou sejaresponse.setHeader(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE);
) - Jetty nunca relata muitas conexões abertas – sempre muito poucas.
- PF/IPFW não está sendo usado atualmente
- nginx -
reset_timedout_connection
está ativado
Não consigo descobrir como fazer com que o nginx ou o jetty fechem a conexão à força. Isso é simplesmente algo que precisa ser corrigido no Jetty para que ele feche totalmente o soquete após a conclusão da solicitação?
Muito obrigado antecipadamente
EDITAR:esqueci minha configuração do 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;
EDITAR2: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 está em LAST_ACK
), mas por que isso não está superando? O Nginx está mantendo a conexão aberta com o back-end por algum motivo?
Responder1
OK, bem, finalmente consegui convencer Jetty a jogar bem.
Só para recapitular, aqui está a aparência das minhas conexões 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 nginx e Jetty
1 FIN_WAIT_2
3 LISTEN
14 ESTABLISHED
Já fechei toda a conexão e EndPoint
(chamando close()
o EndPoint
closes do subjacente SocketChannel
) 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 sofisticado é necessário)
No entanto, isso ainda resultou no preenchimento de todo o servidor com LAST_ACK ... O que fez com que eles finalmente desaparecessem foi a ativação SO_LINGER
(e o fechamento forçado do soquete imediatamente, sem tempo limite)
connector.setSoLingerTime(0);