Slow or failed connections to Oracle Database using Java

I have faced an issue with a program (who uses a old Java 1.6 runtime) and tires to connect to an Oracle Database, the program sometimes connects in few seconds, sometimes need minutes and sometimes fails (and in the database alert logs appears an ORA-3136 due a client connection time-out).

The issue are not related with the database tasks executed by the program, a simple connection/disconnection procedure faces the same problem (without execute any sentence on the database).

In the same server connections using “sqlplus”, using the same Oracle Instant Client installation as the Java application works without any problem and are near “immediate”, this discard firewalls, networking or Oracle connection string issues.

Finally have found the issue, the Java program uses some “random numbers” to encrypt the connection info, and the lack of these numbers causes the failures.

To solve the issue is necessary to define a different origin for random numbers than the default (ho generates “good” random numbers but too slow in most cases).

The parameter to define the origin of random numbers is this: -Djava.security.egd=, and one of the available choices on Linux for the “random origin” is /dev/urandom.


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

Basically the Linux operating system have two “built-in” origins of random numbers:

/dev/random This is the one used by default as “origin of randomness” in older releases of Java, this device blocks the processes trying to read numbers when the numbers are exhausted (the processes waits until numbers are available again).

/dev/urandom This is the “non blocking” random source (always have numbers). It seems that the numbers from “/dev/urandom” are of “less random quality” than the ones from “/dev/random”, but today exist some controversy about this.

The last releases of Java have have an internal procedure to generate random numbers and seems to not relay on none of the above if not instructed to do so explicitly. Anyway this internal procedure takes more time to execute than the use of “/dev/urandom”, then if your needs of “quality randomness” are not so high seems a good idea to use “/dev/urandom”.

This in an example program ho connects to an Oracle Database (without execute any sentence).


import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.SQLException;

public class OracleJDBCExample {

public static void main(String[] argv) {

try {

Class.forName("oracle.jdbc.driver.OracleDriver");

} catch (ClassNotFoundException e) {

System.out.println("Oracle JDBC Driver issue.....");
e.printStackTrace();
return;

}

Connection connection = null;

try {

connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.1:1521:mydb", "system", "mysecret");

} catch (SQLException e) {

System.out.println("Connection to Oracle Database failed");
e.printStackTrace();
return;

}

if (connection != null) {
System.out.println("Succesful connection");
}

}

}

Note: At same time you execute this program is possible to check the available number of elements on the “random pool” origin of “/dev/random” with this sentence:

watch -n 1 cat /proc/sys/kernel/random/entropy_avail

And these are the results, using default parameters (internal generator):


user@machine:$ java -version
openjdk version "9-internal"
OpenJDK Runtime Environment (build 9-internal+0-2016-04-14-195246.buildd.src)
OpenJDK 64-Bit Server VM (build 9-internal+0-2016-04-14-195246.buildd.src, mixed mode)
user@machine:$ time java -cp ./instantclient_12_1/ojdbc7.jar:OracleJDBCExample.jar OracleJDBCExample
Succesful connection

real    0m5.751s
user    0m5.624s
sys    0m0.076s

And if use “/dev/urandom” as source:


user@machine:$ time java -Djava.security.egd=file:/dev/urandom -cp ./instantclient_12_1/ojdbc7.jar:OracleJDBCExample.jar OracleJDBCExample
Succesful connection

real    0m0.709s
user    0m0.632s
sys    0m0.052s

And if force to use “/dev/random” (maybe the firsts executions works, but when the pool is empty or near empty….):


user@machine:$ time java -Djava.security.egd=file:/dev/random -cp ./instantclient_12_1/ojdbc7.jar:OracleJDBCExample.jar OracleJDBCExample
Connection to Oracle Database failed
java.sql.SQLRecoverableException: IO Error: Connection reset
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:752)
at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:666)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:566)
at java.sql.DriverManager.getConnection(java.sql@9-internal/DriverManager.java:698)
at java.sql.DriverManager.getConnection(java.sql@9-internal/DriverManager.java:247)
at OracleJDBCExample.main(OracleJDBCExample.java:25)
Caused by: java.net.SocketException: Connection reset
at java.net.SocketOutputStream.socketWrite(java.base@9-internal/SocketOutputStream.java:113)
at java.net.SocketOutputStream.write(java.base@9-internal/SocketOutputStream.java:153)
at oracle.net.ns.DataPacket.send(DataPacket.java:209)
at oracle.net.ns.NetOutputStream.flush(NetOutputStream.java:215)
at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:302)
at oracle.net.ns.NetInputStream.read(NetInputStream.java:249)
at oracle.net.ns.NetInputStream.read(NetInputStream.java:171)
at oracle.net.ns.NetInputStream.read(NetInputStream.java:89)
at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:123)
at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:79)
at oracle.jdbc.driver.T4CMAREngineStream.unmarshalUB1(T4CMAREngineStream.java:429)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:397)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:257)
at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:437)
at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:954)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:639)
... 6 more

real    1m53.685s
user    0m0.632s
sys    0m0.076s

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s