Warum komme ich plötzlich nicht mehr an die Datenbank?
Mit einer unserer Java-Anwendungen hatten wir plötzlich ein unerklärliches Zugriffs-Problem auf die darunter liegende Oracle Datenbank. Nach der Installation der Anwendung auf einer neuen Virtuellen Maschine scheiterte jeder JDBC-Zugriff auf die Datenbank mit dem Fehler:
[code gutter=”false”]java.sql.SQLRecoverableException: I/O-Fehler: Connection reset[/code]
obwohl der Datenbank Server selbst nicht verändert wurde. Wir konnten den Fehler mit einer einfachen Test Klasse repoduzieren und es wurde schnell klar, es liegt weder an der Anwendung, noch am Datenbank-Server.
Ursache für den Connection reset
Der Oracle JDBC Treiber verschlüsselt die Verbindung zum Datenbank-Server und nutzt für die Verschlüsselung u.a. die Klasse SecureRandom
. Diese Klasse liefert Zufallszahlen basierend auf der Entropie des Systems (1) (2). Die Entropie wird in der Regel über Hardware gebildet, z.B. Maus-Bewegungen und Tastaur-Eingaben oder auch durch spezielle “randomness generators”. Der Zugriff erfolgt über spezielle Devices: /dev/random
oder /dev/urandom
, wobei /dev/random
der Default ist. Das Besondere an /dev/random
ist, dass der Zugriff blockiert, wenn die Entropie des Systems nicht groß genug ist. Dies führt dann zu der Exception “SQLRecoverableException: I/O-Fehler: Connection reset
” beim JDBC Zugriff auf die Datenbank.
Was ist bei der Installation auf der neuen VM passiert?
Bei der neuen Virtuellen Maschine handelt es sich um ein Serversystem ohne große Maus-Bewegungen oder Tastaur-Eingaben und eine anderweitige Entropiequelle ist nicht eingerichtet. D.h. nach Installation und Start der Anwendung ist die Entropie des Systems zu klein für einen nicht blockierenden Zugriff auf /dev/random
.
Die Lösung
Als Alternative zu /dev/random
kann auch /dev/urandom
benutzt werden. Der Zugriff auf /dev/urandom
blockiert nicht, wenn zu wenig Entropie vorhanden ist – das wollen wir gerade erreichen. Allerdings ist in diesem Fall die Verschlüsselung nicht so gut und kann theoretisch geknackt werden. In der Anwendung haben wir uns trotzdem für diesen Weg entschieden, weil es sich bei der Datenbank-Verbindung um eine für Dritte unzugängliche Verbindung handelt. Die Benutzung von /dev/urandom
wird über eine System Property konfiguriert:
[code gutter=”false”]-Djava.security.egd=file:///dev/urandom[/code]
Dieses Problem existiert im Prinzip bei allen verschlüsselten Verbindungen. Durch das Setzten der System Property java.security.egd
ist natürlich nicht nur der Oracle JDBC Treiber betroffen, sondern auch andere Benutzungen von SecureRandom
. Auch in anderen Umgebungen gibt es ein ähnliches Problem, siehe Apache HTTP Webserver SSLRandomSeed Direktive.
Michael Bouschen
Michael Watzek
Quellen:
(1) Oracle JDBC intermittent Connection Issue
(2) ORACLE IO exception – Connection reset or Timeout reached – 30s – for process