Linux下运行java程序(jdk 1.7),该程序会获取Oracle数据库连接,为了提高处理速度,采用了多个进程并行启动处理,这时,偶尔会发生数据库连接获取超时失败的异常发生.而且windows环境下没有问题.
java.sql.SQLException: IO Error: End of TNS data channel
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:458)
at oracle.jdbc.driver.PhysicalConnection.(PhysicalConnection.java:546)
at oracle.jdbc.driver.T4CConnection.(T4CConnection.java:236)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
或者
java.sql.SQLException: IO Error: Connection reset
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:467)
at oracle.jdbc.driver.PhysicalConnection.(PhysicalConnection.java:546)
at oracle.jdbc.driver.T4CConnection.(T4CConnection.java:236)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
解决办法:
java启动的时候添加启动参数 「-Djava.security.egd=file:/dev/./urandom」
注意:「-Djava.security.egd=file:/dev/urandom」的话,相当于「-Djava.security.egd=file:/dev/random」
原因分析
Oracle的JDBC driver程序里面在获取db连接的时候用到了java的SecureRandom,来获取随机字节数据流,用来产生随机数,-Djava.security.egd配置的就是随机数据收集伪设备,linux下有两种:
1./dev/random,利用系统中断来生成随机数据,所以当系统不是很繁忙的时候,中断数很少,那么调用进程就会进入等待状态,直到有足够用的中断数的时候,才会返回随机数,而这时可能已经发生getConnection超时了
2./dev/urandom,不利用系统中断来生成随机数,所以不会造成调用进程等待
所以,我们的遇到的情况必须使用urandom才行,由于java的bug,即使指定file:/dev/urandom,SecureRandom使用的仍然是random,为了绕过这个bug,我们发现了「-Djava.security.egd=file:/dev/./urandom」这种配置方式,来达到我们使用urandom的目的.
为了验证配置前后的速度,可以用下面的小程序进行对比确认
JRand.java
import java.security.SecureRandom;
class JRand {
public static void main(String args[]) throws Exception {
System.out.println("Ok: " +
SecureRandom.getInstance("SHA1PRNG").nextLong());
}
}
time java -Djava.security.egd=file:/dev/urandom JRand
time java -Djava.security.egd=file:/dev/./urandom JRand