Ich habe eine FreeBSD-Maschine mit Jails – zwei im Besonderen, eine, auf der nginx läuft, und eine andere, auf der ein Java-Programm läuft, das Anfragen über Jetty (eingebetteter Modus) akzeptiert.
Jetty empfängt ständig über 500 Anfragen/Sekunde und es gab in letzter Zeit ein Problem, bei dem ich ständig über60.000Verbindungen im LAST_ACK-Status zwischen Nginx und Jetty.
Verteilung aller Verbindungen (beinhaltet auch einige andere Dienste, insbesondere 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
Verteilung von Nginx -> Jetty-Verbindungen
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
Ich würde es vorziehen, wenn bei jeder Anfrage die Verbindung vollständig geschlossen wird. Die Clientanfragen liegen etwa 10 Minuten auseinander, daher müssen Verbindungen geschlossen werden.
Einige der Verbindungen,
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..
- Auf Jettys Seite habe ich
maxIdleTime
2000 eingestellt - vorher waren alle Verbindungen vorhanden,ESTABLISHED
aber jetzt sind sieLAST_ACK
- Auf Jettys Seite habe ich eingestellt
Connection: close
(dhresponse.setHeader(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE);
) - Jetty meldet nie viele offene Verbindungen – immer sehr wenige.
- PF/IPFW wird derzeit nicht verwendet
- nginx -
reset_timedout_connection
ist eingeschaltet
Ich kann nicht herausfinden, wie ich Nginx oder Jetty dazu bringe, die Verbindung zwangsweise zu schließen. Ist das einfach etwas, das in Jetty behoben werden muss, damit es den Socket nach Abschluss der Anforderung vollständig schließt?
vielen Dank im Voraus
BEARBEITEN:habe meine Nginx-Konfiguration für das Proxy-Setup vergessen-
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 zu zwingen, die Verbindung über zu schließen, request.getConnection().getEndPoint().close()
bewirkt nichts – es ist offensichtlich, dass die Verbindung geschlossen WIRD (da sie in ist LAST_ACK
), aber warum kommt sie nicht darüber hinaus? Hält Nginx aus irgendeinem Grund die Verbindung zum Backend offen?
Antwort1
OK, ich konnte Jetty endlich davon überzeugen, brav mitzuspielen.
Zur Wiederholung: So sehen meine Verbindungen jetzt maschinenweit aus:
24 LAST_ACK
36 CLOSING
117 FIN_WAIT_2
175 ESTABLISHED
351 FIN_WAIT_1
4725 TIME_WAIT
Und zwischen nginx und Jetty
1 FIN_WAIT_2
3 LISTEN
14 ESTABLISHED
Ich habe bereits die gesamte Verbindung geschlossen und EndPoint
( close()
durch den Aufruf EndPoint
wird die zugrunde liegende Verbindung geschlossen SocketChannel
) diese praktische Methode verwendet:
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();
}
(Ich sende maximal eine Zeile an den Client, es ist also nichts Ausgefallenes erforderlich)
Dies führte jedoch trotzdem dazu, dass der gesamte Server mit LAST_ACK gefüllt wurde ... Was diese schließlich verschwinden ließ, war die Aktivierung SO_LINGER
(und das zwangsweise sofortige Schließen des Sockets, ohne Timeout).
connector.setSoLingerTime(0);