HOWTO · Java
Java.Net.SocketTimeoutException: Zeitüberschreitung beim Lesen unter Tomcat
Im heutigen Tutorial werden mögliche Gründe und Lösungen für die java.net.SocketTimeoutException diskutiert: Read timed out under Tomcat in Java.
Auf dieser Seite
Wenn Java java.net.SocketTimeoutException: Read timed out meldet, hat ein Socket-Lesevorgang keine Daten erhalten, bevor die dafür konfigurierte Wartezeit abgelaufen ist. Aus der Meldung allein geht nicht hervor, ob die Verzögerung von einem entfernten Dienst, dem Netzwerk, der Anwendungsverarbeitung oder dem vom Aufrufer konfigurierten Timeout verursacht wurde. Ermittle zuerst den fehlgeschlagenen Lesevorgang und passe dann nur den dafür geltenden Timeout an.
Was java.net.SocketTimeoutException: Read timed out bedeutet
Ein Lese-Timeout begrenzt, wie lange ein Java-Socket-Lesevorgang auf Daten wartet. Er unterscheidet sich von einem Verbindungs-Timeout, der eine andere Phase der Kommunikation steuert. Ein Stacktrace kann zeigen, ob der Lesevorgang zu einem HTTP-Client, einem Datenbanktreiber oder zum Anwendungscode gehört. Nutze diese Aufrufstelle und die zugehörigen Protokolle, um den Vorgang zu ermitteln.
Die Meldung beweist nicht, dass Tomcat einem Client nicht geantwortet hat. Der Java-Prozess, der sie protokolliert hat, liest möglicherweise selbst von einem vorgeschalteten Dienst; außerdem kann der Kommunikationspartner Daten gesendet haben, bevor der Lesevorgang ablief, der den Timeout ausgelöst hat. Gleiche den Stacktrace, sofern verfügbar, mit Anforderungs-IDs, Zeitstempeln und Protokollen beider Seiten ab.
Ermitteln, welcher Timeout abläuft
Suche im Stacktrace der Ausnahme nach dem ersten Anwendungs- oder Bibliotheksaufruf, der den Lesevorgang gestartet hat. Ermittle, ob dabei eine HTTP-Antwort, ein Datenbankergebnis oder ein anderer Socket gelesen wird. Prüfe anschließend die Einstellungen und die Dokumentation dieses Clients auf den Lese- oder Antwort-Timeout. Ein Browser- oder Frontend-Timeout ist nur dann relevant, wenn dieser Client den abgelaufenen Lesevorgang tatsächlich steuert.
Wenn Tomcat im Aufrufpfad erscheint, stelle fest, welcher Prozess den Fehler protokolliert hat und welche Verbindung er gelesen hat. Ein für einen ausgehenden Java-Client konfigurierter Timeout ist unabhängig von einer Einstellung am Tomcat Connector. Leite die zuständige Einstellung nicht allein aus dem Ausnahmetext ab.
Den passenden Tomcat-Timeout konfigurieren
connectionTimeout ist eine Tomcat-Connector-Einstellung. Ihr genaues Verhalten und ihre Standardwerte hängen jedoch von der verwendeten Tomcat-Version und dem Connector ab. Sie ist nicht mit dem Socket-Lese-Timeout eines Java-Clients gleichzusetzen. Lies die Dokumentation zur Connector-Konfiguration für Tomcat 10.1 und prüfe anschließend die Dokumentation der von dir eingesetzten Tomcat-Version. Vergewissere dich, dass die Einstellung für den im Stacktrace ermittelten Vorgang gilt. Da die bereitgestellten Informationen keine Tomcat-Version nennen, lässt sich keine sichere Änderung an der Connector-XML empfehlen.
Bei einem Java-Client, der einen Socket besitzt, konfiguriert Socket.setSoTimeout die Lesevorgänge auf diesem Socket. Das Programm liest den konfigurierten Wert wieder aus und gibt ihn mit der englischen Beschriftung „Read timeout:“ aus:
import java.io.IOException;
import java.net.Socket;
class ReadTimeoutSetup {
public static void main(String[] args) throws IOException {
try (Socket socket = new Socket()) {
socket.setSoTimeout(5000);
System.out.println("Read timeout: " + socket.getSoTimeout() + " ms");
}
}
}
Read timeout: 5000 ms
Dieses Beispiel stellt keine Verbindung zu einem Server her und ändert auch nicht die Tomcat-Konfiguration. Wende eine clientseitige Einstellung nur in der Komponente an, die den betroffenen Lesevorgang steuert, und gleiche den gewählten Wert mit der API dieses Clients und den betrieblichen Anforderungen ab.
Verzögerungen im Netzwerk, Server und in der Anwendung untersuchen
Vergleiche Zeitstempel und Anforderungs-IDs beim Aufrufer, in Tomcat und bei vorgeschalteten Diensten. Suche nach einem Zeitraum ohne Antwortdaten und gleiche ihn dann mit Netzwerkfehlern, Serverprotokollen und Anwendungstraces ab. Verzögerte Daten können durch Netzwerklatenz, langsame Anwendungsverarbeitung, eine langsame Datenbankabfrage, Ressourcenkonflikte oder gleichzeitige Last verursacht werden. Das sind Ansatzpunkte für die Untersuchung, keine Schlussfolgerungen, die sich allein aus der Ausnahme ergeben.
Prüfe für denselben Zeitraum die CPU-, Speicher-, Thread-, Verbindungspool- und Datenbankmetriken. Ermittle, ob die betreffende Anforderung die Anwendung erreicht hat und ob ein nachgelagerter Aufruf oder eine Abfrage länger als üblich gedauert hat. Wenn der Dienst hinter einem Proxy oder Load Balancer läuft, vergleiche dessen Timeout und Protokolle mit den Zeitabläufen auf Client- und Serverseite. Ändere jeweils nur eine passende Einstellung und beobachte, ob der konkrete Lesevorgang abgeschlossen wird. Untersuche zugleich weiter die Ursache der Verzögerung.
Lange Anfragen sicher behandeln
Wenn ein Vorgang berechtigterweise länger dauert, als eine synchrone Anfrage warten kann, solltest du eine asynchrone Verarbeitung erwägen: Sende eine Annahmebestätigung mit einer Auftrags-ID zurück, führe die Arbeit getrennt aus und ermögliche dem Client, den Abschluss abzufragen. So muss eine Anfrage nicht während der gesamten Verarbeitung offen bleiben. Dafür muss die Anwendung diese Vorgehensweise unterstützen und Fehler oder Fortschritt verständlich melden können.
Wenn eine längere Wartezeit angemessen ist, erhöhe nur den Timeout, der für den ermittelten Lesevorgang gilt, und stimme die zugehörigen Grenzwerte von Client, Proxy und Server aufeinander ab. Übermäßig lange Wartezeiten können Threads, Sockets oder andere Ressourcen binden und verschleiern, dass ein Dienst langsamer wird. Leite die Werte aus beobachteten Anforderungszeiten und der verfügbaren Kapazität ab und überwache sowohl die Abschlussraten als auch den Ressourcenverbrauch.