Problema de conexión intermitente de Oracle JDBC

Estoy experimentando un problema muy extraño. Este es un uso muy simple de la conexión JDBC a una base de datos Oracle.

OS: Ubuntu Java Version: 1.5.0_16-b02 1.6.0_17-b04 Database: Oracle 11g Release 11.1.0.6.0 

Cuando uso el archivo jar OJDBC14.jar se conecta a la base de datos cada vez Cuando uso el archivo jar OJDBC5.jar se conecta algunas veces y otras veces arroja un error (como se muestra a continuación) Si recompilo con Java 6 y use OJDBC6.jar obtengo los mismos resultados que OJDBC5.jar

Necesito características específicas en JODB5.jar que no están disponibles en OJDBC14.jar

Algunas ideas

Error

 > Connecting to oracle java.sql.SQLException: Io exception: Connection reset at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:74) at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:110) at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:171) at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:227) at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:494) at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:411) at oracle.jdbc.driver.PhysicalConnection.(PhysicalConnection.java:490) at oracle.jdbc.driver.T4CConnection.(T4CConnection.java:202) at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:33) at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:474) at java.sql.DriverManager.getConnection(DriverManager.java:525) at java.sql.DriverManager.getConnection(DriverManager.java:171) at TestConnect.main(TestConnect.java:13) 

Código

A continuación está el código que estoy usando

 import java.io.*; import java.sql.*; public class TestConnect { public static void main(String[] args) { try { System.out.println("Connecting to oracle"); Connection con=null; Class.forName("oracle.jdbc.driver.OracleDriver"); con=DriverManager.getConnection( "jdbc:oracle:thin:@172.16.48.100:1535:sample", "JOHN", "90009000"); System.out.println("Connected to oracle"); con.close(); System.out.println("Goodbye"); } catch(Exception e) { e.printStackTrace(); } } } 

Hay una solución provista para este problema en algunos de los foros de OTN ( https://kr.forums.oracle.com/forums/thread.jspa?messageID=3699989 ). Pero, la causa raíz del problema no se explica. A continuación está mi bash de explicar la causa raíz del problema.

Los controladores Oracle JDBC se comunican con el servidor de Oracle de forma segura. Los controladores utilizan la clase java.security.SecureRandom para recostackr entropy para asegurar la comunicación. Esta clase se basa en el soporte nativo de la plataforma para reunir la entropía.

La entropía es la aleatoriedad recostackda / generada por un sistema operativo o aplicación para su uso en criptografía u otros usos que requieren datos aleatorios. Esta aleatoriedad a menudo se recostack de fonts de hardware, ya sea a partir de los ruidos de hardware, datos de audio, movimientos del mouse o generadores de aleatoriedad especialmente provistos. El kernel reúne la entropía y la almacena; es un grupo de entropía y pone a disposición los datos del carácter aleatorio para los procesos o aplicaciones del sistema operativo mediante los archivos especiales / dev / random y / dev / urandom .

La lectura de / dev / random drena el grupo de entropía con la cantidad solicitada de bits / bytes, proporcionando un alto grado de aleatoriedad a menudo deseado en operaciones criptográficas. En el caso, si el grupo de entropía está completamente agotado y no hay suficiente entropía disponible, la operación de lectura en / dev / random bloquea hasta que se obtenga entropía adicional. Debido a esto, las aplicaciones que leen desde / dev / random pueden bloquearse durante un período de tiempo aleatorio.

En contraste con lo anterior, la lectura de / dev / urandom no bloquea. La lectura de / dev / urandom también drena el grupo de entropía, pero cuando no hay entropía suficiente, no bloquea sino que reutiliza los bits de los datos aleatorios parcialmente leídos. Se dice que esto es susceptible a los ataques criptoanalíticos. Esta es una posibilidad teórica y por lo tanto se desaconseja leer de / dev / urandom para recostackr aleatoriedad en operaciones criptográficas.

La clase java.security.SecureRandom , de forma predeterminada, se lee desde el archivo / dev / random y, por lo tanto, a veces se bloquea durante un período de tiempo aleatorio. Ahora, si la operación de lectura no retorna durante un período de tiempo requerido, el servidor Oracle agota el tiempo de espera del cliente (los controladores jdbc, en este caso) y elimina la comunicación cerrando el socket desde su final. El cliente cuando intenta reanudar la comunicación después de regresar de la llamada de locking encuentra la excepción IO. Este problema puede ocurrir aleatoriamente en cualquier plataforma, especialmente, donde la entropía se recostack a partir de ruidos de hardware.

Como se sugirió en el foro de OTN, la solución a este problema es anular el comportamiento predeterminado de la clase java.security.SecureRandom para usar la lectura no bloqueante de / dev / urandom en lugar de la lectura de locking de / dev / random . Esto se puede hacer agregando la siguiente propiedad del sistema -Djava.security.egd = file: /// dev / urandom a la JVM. Aunque esta es una buena solución para las aplicaciones como los controladores JDBC, se desaconseja para las aplicaciones que realizan operaciones criptográficas básicas, como la generación de claves criptográficas.

Otras soluciones podrían ser el uso de diferentes implementaciones de semillas al azar disponibles para la plataforma que no dependan de los ruidos del hardware para reunir la entropía. Con esto, es posible que aún deba sobrescribir el comportamiento predeterminado de java.security.SecureRandom .

Aumentar el tiempo de espera del socket en el lado del servidor de Oracle también puede ser una solución, pero los efectos secundarios deben evaluarse desde el punto de vista del servidor antes de intentar esto.

Estaba enfrentando exactamente el mismo problema. Con Windows Vista no pude reproducir el problema, pero en Ubuntu reproduje el “restablecimiento de la conexión”: error constantemente.

Encontré http://forums.oracle.com/forums/thread.jspa?threadID=941911&tstart=0&messageID=3793101

De acuerdo con un usuario en ese foro:

Abrí un boleto con Oracle y esto es lo que me dijeron.

java.security.SecureRandom es una API estándar proporcionada por sun. Entre los diversos métodos ofrecidos por esta clase void nextBytes (byte []) es uno. Este método se usa para generar bytes aleatorios. Los controladores Oracle 11g JDBC usan esta API para generar números aleatorios durante el inicio de sesión. Los usuarios que usan Linux han encontrado SQLException (“Io exception: Connection reset”).

El problema es doble

  1. La JVM intenta listar todos los archivos en / tmp (o el directorio alternativo tmp establecido por -Djava.io.tmpdir) cuando se invoca SecureRandom.nextBytes (byte []). Si la cantidad de archivos es grande, el método tarda mucho tiempo en responder y, por lo tanto, provoca que el servidor agote el tiempo de espera.

  2. El método void nextBytes (byte []) usa / dev / random en Linux y en algunas máquinas que no tienen el número aleatorio que genera el hardware, la operación se ralentiza hasta el punto de detener todo el proceso de inicio de sesión. En última instancia, el usuario encuentra SQLException (“Io exception: Connection reset”)

Los usuarios que actualicen a 11g pueden enfrentar este problema si el sistema operativo subyacente es Linux que se ejecuta en un hardware defectuoso.

Causa La causa de esto aún no se ha determinado exactamente. Podría ser un problema en su hardware o el hecho de que por alguna razón el software no puede leer dev / random

Solución Cambie la configuración de su aplicación, por lo que agrega el siguiente parámetro al comando java:

-Djava.security.egd = archivo: / dev /../ dev / urandom

Hicimos este cambio en nuestro archivo java.security y se ha eliminado el error.

que resolvió mi problema

Un mensaje de error de “restablecimiento de conexión” generalmente significa que el otro lado ha abortado la conexión durante el bash de crear una conexión (el protocolo de enlace). Esto tiene muchas causas posibles. Un error en el controlador JDBC, un tiempo de espera en el lado de DB, un reinicio de la base de datos, la DB se está quedando sin conexiones disponibles, mala calidad de red, mal virusscanner / firewall / proxy, etc.

Como ocurre de manera intermitente, un error en el controlador JDBC puede ser excluido menos o más. Dejado detrás de las causas posibles restantes. Sugiero comenzar mirando en los registros del servidor de bases de datos.

Es difícil de decir, pero si compruebo la versión actual del controlador JDBC. Asegúrate de que sea 11.1.0.6.

Oracle no incluye la versión de la base de datos en el nombre del archivo. Entonces el controlador para 11.2 es exactamente el mismo nombre que el driver para 11.1 – ojdbc5.jar. Extraería el archivo jar del controlador y encontraría el archivo MANIFEST.MF, que contendrá información de la versión. Asegúrese de que la versión del controlador JDBC coincida con la versión de su base de datos. Sospecho que puede ser un problema de versión, ya que no hay un archivo jar llamado ojdbc14.jar en la página de descarga de 11.1.0.6 de Oracle.

Si la versión coincide, me quedo sin ideas 🙂

Encontré este enlace para el mismo problema con el sistema de 64 bits, el controlador jdbc 11g y el restablecimiento de la conexión: http://forums.oracle.com/forums/thread.jspa?messageID=3793101

Solo para aclarar, al menos de lo que encontramos de nuestro lado. Es un problema con la configuración del aleatorizador para Linux en la distribución JDK, y lo encontramos en Java6, no estoy seguro acerca de Java7. La syntax para Linux para el aleatorizador es file: /// dev / urandom, pero la entrada en el archivo es (probablemente sea / copiada de Windows) como archivo: / dev / urandom. Entonces, Java probablemente recurra al valor predeterminado, que es / dev / random. ¡Y que no funciona en una máquina sin cabeza!

Otra cosa que me causaba este problema era tener la configuración HOSTNAME incorrecta. Mi bash de conexión fue ahorcado en:

 "main" prio=10 tid=0x00007f7cc8009000 nid=0x2f3a runnable [0x00007f7cce69e000] java.lang.Thread.State: RUNNABLE at java.net.Inet4AddressImpl.getLocalHostName(Native Method) at java.net.InetAddress.getLocalHost(InetAddress.java:1444) at sun.security.provider.SeedGenerator$1.run(SeedGenerator.java:176) at sun.security.provider.SeedGenerator$1.run(SeedGenerator.java:162) at java.security.AccessController.doPrivileged(Native Method) 

Así que asegúrese de tener una entrada para su nombre de host en /etc/hosts/ .

Si emite un comando de hostname como este:

 $ hostname my.server.com 

Necesitas una línea en tu /etc/hosts :

 127.0.0.1 my my.server.com 

La causa principal de este problema tiene que ver con las versiones de autenticación de usuario. Para cada usuario de base de datos, múltiples verificadores de contraseña se mantienen en la base de datos. Por lo general, cuando actualiza su base de datos, se agregará un nuevo verificador de contraseñas a la lista, uno más fuerte. La siguiente consulta muestra las versiones del verificador de contraseñas disponibles para cada usuario. Por ejemplo:

 SQL> SELECT PASSWORD_VERSIONS FROM DBA_USERS WHERE USERNAME='SCOTT'; PASSWORD_VERSIONS ----------------- 11G 12C 

Al actualizar a un controlador más nuevo, puede usar una versión más nueva del verificador porque el controlador y el servidor negocian el verificador más fuerte posible para ser utilizado. Esta nueva versión del verificador será más segura e implicará la generación de números aleatorios más grandes o el uso de funciones de hashing más complejas que pueden explicar por qué usted ve problemas al establecer conexiones JDBC. Como se menciona en otras respuestas que usan /dev/urandom normalmente resuelve estos problemas. También puede decidir degradar el verificador de contraseñas y hacer que el controlador más nuevo use el mismo verificador de contraseñas más antiguo que estaba usando su controlador anterior. Por ejemplo, si desea utilizar el verificador de contraseñas 10G (solo para fines de prueba), primero debe asegurarse de que esté disponible para su usuario. Establezca SQLNET.ALLOWED_LOGON_VERSION_SERVER=8 en sqlnet.ora en el servidor. Entonces:

 SQL> alter user scott identified by "tiger"; User altered. SQL> SELECT PASSWORD_VERSIONS FROM DBA_USERS WHERE USERNAME='SCOTT'; PASSWORD_VERSIONS ----------------- 10G 11G 12C 

Luego puede forzar al controlador delgado JDBC a usar el verificador 10G estableciendo esta propiedad JDBC oracle.jdbc.thinLogonCapability="o3" . Si se encuentra con el error "ORA-28040: No matching authentication protocol" , significa que su servidor no permite el uso del verificador 10G. Si ese es el caso, entonces necesita verificar su configuración nuevamente.

Tenga en cuenta que la solución sugerida de usar / dev / urandom funcionó la primera vez para mí, pero no funcionó siempre después de eso.

DBA en mi empresa cambió de ‘pancartas de red SQL *’ y eso lo solucionó de forma permanente para mí con o sin lo anterior.

No sé qué son los “banners de SQL * net”, pero espero incluir aquí esta información que, si tiene (es) un DBA, (él) sabría qué hacer.

Deshabilitar SQL Net Banners nos salvó .

-Djava.security.egd = file: / dev /./ urandom debe estar en lo cierto! no -Djava.security.egd = file: / dev /../ dev / urandom o -Djava.security.egd = file: /// dev / urandom

Según Bug https://bugs.openjdk.java.net/browse/JDK-6202721

Java no consintirá -Djava.security.egd = file: / dev / urandom

Debería ser -Djava.security.egd = file: / dev /./ urandom

OracleXETNSListener: este servicio debe iniciarse si se deshabilitó.

 run -> services.msc 

y busca esos servicios