Oracle JDBC 连接卡死后 Connection Reset

jstorm项目新增一台linux主机,程序运行的时候报错如下:


我把研发的源代码拿过来找到对应的LoadSysParam.init();单独写了一个测试程序,在新主机上连续运行几次后就会重现该问题报错如下:

Exception in thread "main" org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (IO 错误: Connection reset)

    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80)

    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:573)

    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637)

    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:666)

    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:674)

    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:714)

    at com.tydic.common.db.DBManager.getSql(DBManager.java:507)

    at com.tydic.common.db.DBManager.getListBySqlCode(DBManager.java:87)

    at com.tydic.notice.work.load.LoadSysParam.LoadMsgStruct(LoadSysParam.java:239)

    at com.tydic.notice.work.load.LoadSysParam.load(LoadSysParam.java:151)

    at com.tydic.notice.work.load.LoadSysParam.init(LoadSysParam.java:142)

    at com.tydic.main.LoadMain.main(LoadMain.java:12)

Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (IO 错误: Connection reset)

    at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1549)

    at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1388)

    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)

    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)

    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)

    ... 11 more

Caused by: java.sql.SQLRecoverableException: IO 错误: Connection reset

    at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:752)

    at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:662)

    at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)

    at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:560)

    at org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38)

    at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:582)

    at org.apache.commons.dbcp.BasicDataSource.validateConnectionFactory(BasicDataSource.java:1556)

    at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1545)

    ... 15 more

Caused by: java.net.SocketException: Connection reset

    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:115)

    at java.net.SocketOutputStream.write(SocketOutputStream.java:155)

    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:433)

    at oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:950)

    at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:639)

    ... 22 more

网上搜索"linux oracle connection reset",得到如下信息:

-----------------------------------------------------------------------------------

这绝对是我碰计算机以来遇到的第一大坑!

症状:

在Linux主机上远程登录,执行一个简单的Oracle的JDBC连接程序(jar包),结果硬生生的卡在了连接建立验证阶段,然后等上几分钟后因为连接超时,连接被远端的Oracle服务器reset,于是报了connection reset exception

原因:

参考:http://www.usn-it.de/index.php/2009/02/20/oracle-11g-jdbc-driver-hangs-blocked-by-devrandom-entropy-pool-empty/

如参考材料中所述,oracle JDBC在建立连接时需要一些随机数据用以加密session token之类的东西,而这个随机数据源默认用的是/dev/random,如果不是,反正也是一个能让人慢的抓狂的发生源。Linux有个内核熵池(感觉太装B了),通过搜集键盘,鼠标,中断,磁盘操作来产生随机数据,可以通过以下命令查看当前的熵值:

cat /proc/sys/kernel/random/entropy_avail

由于执行程序的主机没有图形界面只是通过远程ssh进行连接,那么熵值来源就少了两个,如果机器比较空闲则后面两个来源也少了,结果就是等半天来不了一个随机数,可以通过一下命令体验一下,用/dev/random憋出个随机数是多难

dd if =/dev/random of=rnd_file bs=1 count=64

如果侥幸执行的很快,可以多试几次把积累起来的熵值用掉,可以通过前面所述的方法查看当前熵值数目

Linux中还有个随机数发生器,/dev/urandom,如其名字所述,不那么随机的随机发生器,就是伪随机的,当然会快很多。参考资料中给出的把随机源修改为/dev/urandom的方法,即在执行java程序加入命令行参数:

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

可是似乎不起作用。那么手工来增大熵值吧,可以执行一下命令

for   i in {1..100000}; do   cat /proc/sys/kernel/random/entropy_avail;done;

就是反复打印当前熵值10万次,当然根据自己测试的结果当熵值到达240+时,可以按ctrl+c终止这个命令,此时再去执行Oracle JDBC程序,就可以连接成功了(保险一点可以等熵值更大时终止命令)。虽然不是实用的解决方案,但至少确定了问题所在。为了这个事,人都快奔溃了。

解决方案:

安装一个为提供提供熵的程序包

   sudo apt-get install haveged
安装后需要手动执行
   /usr/sbin/haveged -w 1024 -v 1
--------------------
通过比对新老机器熵值cat /proc/sys/kernel/random/entropy_avail,发现新机器值很小,老机器之很大,感觉这个博客写的应该靠谱
同时又在启动参数上加入-Djava.security.egd=file:///dev/urandom,发现程序不会报错。可以确定就是这个问题导致的。
ps:suse默认是有这个安装包的,rethad默认无此安装包,需要另外装
 
 
 
 
 
 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">





猜你喜欢

转载自www.cnblogs.com/pthwang/p/8949445.html