解決JDBC Connection Reset的問(wèn)題分析
JDBC Connection Reset的問(wèn)題分析
半年前開(kāi)始,項(xiàng)目組測(cè)試MM在驗(yàn)證功能時(shí),經(jīng)常報(bào)怨講測(cè)試環(huán)境上的應(yīng)用在啟動(dòng)時(shí)很慢,偶爾會(huì)報(bào)失敗,遇到類(lèi)似問(wèn)題多數(shù)情況下重新啟動(dòng)一次就可以啟動(dòng)成功,但少數(shù)時(shí)候也有反復(fù)啟動(dòng)不成功的案例。
當(dāng)啟動(dòng)失敗時(shí),日志里有如下的異常,看起來(lái)似乎和網(wǎng)絡(luò)有關(guān)。
java.sql.SQLRecoverableException: I/O Exception: Connection reset
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:281)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:118)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:224)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:296)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:611)
at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:455)
at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:494)
at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:199)
at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:30)
at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:503)
at java.sql.DriverManager.getConnection(DriverManager.java:582)
at java.sql.DriverManager.getConnection(DriverManager.java:154)
應(yīng)用使用的數(shù)據(jù)庫(kù)是Oracle,版本為11g R1和R2,Oracle和應(yīng)用都運(yùn)行在Linux環(huán)境,JDBC驅(qū)動(dòng)是從Oracle官網(wǎng)下載的ojdbc6.jar。
由于這類(lèi)問(wèn)題出現(xiàn)的頻率比較低,出現(xiàn)問(wèn)題的數(shù)據(jù)庫(kù)環(huán)境都被做過(guò)安全加固,加上我忙于其它事情,這個(gè)問(wèn)題就被擱置起來(lái),沒(méi)有去認(rèn)真定位,測(cè)試MM的懷疑都被我以環(huán)境原因的理由搪塞過(guò)去。
最近兩個(gè)月,應(yīng)用在多個(gè)生產(chǎn)環(huán)境部署時(shí)也出現(xiàn)了類(lèi)似的現(xiàn)象,在有些生產(chǎn)環(huán)境,上述問(wèn)題還會(huì)導(dǎo)致雙機(jī)切換不成功或者反復(fù)切換。做現(xiàn)場(chǎng)實(shí)施的同事對(duì)此抱怨很多,對(duì)我們的應(yīng)用產(chǎn)生了懷疑。
看來(lái)這個(gè)問(wèn)題需要認(rèn)真對(duì)待,并且一定要解決了。
現(xiàn)象分析
從測(cè)試MM和現(xiàn)場(chǎng)實(shí)施人員的描述看,這個(gè)問(wèn)題有以下幾個(gè)特征:
- 應(yīng)用啟動(dòng)時(shí)很慢,這時(shí)有很大概率會(huì)失敗;
- 應(yīng)用包括很多組件,其中大部分組件在啟動(dòng)時(shí)都會(huì)嘗試訪問(wèn)數(shù)據(jù)庫(kù)加載一些數(shù)據(jù),而其中一個(gè)組件在訪問(wèn)數(shù)據(jù)庫(kù)時(shí)經(jīng)常會(huì)報(bào)上述異常;
- 當(dāng)啟動(dòng)失敗時(shí),檢查Oracle實(shí)例對(duì)應(yīng)的alert日志時(shí),發(fā)現(xiàn)出現(xiàn)有TNS錯(cuò)誤,樣例如下:
Fatal NI connect error 12170.
VERSION INFORMATION:
TNS for Linux: Version 11.2.0.1.0 - Production
Oracle Bequeath NT Protocol Adapter for Linux: Version 11.2.0.1.0 - Production
TCP/IP NT Protocol Adapter for Linux: Version 11.2.0.1.0 - Production
Time: 11-MAY-2014 22:23:40
Tracing not turned on.
Tns error struct:
ns main err code: 12535
TNS-12535: TNS:operation timed out
ns secondary err code: 12560
nt main err code: 505
TNS-00505: Operation timed out
nt secondary err code: 110
nt OS err code: 0
問(wèn)題定位
TNS錯(cuò)誤
由于實(shí)驗(yàn)室里的Oracle環(huán)境都做過(guò)安全加固,而問(wèn)題現(xiàn)象里有發(fā)現(xiàn)過(guò)TNS錯(cuò)誤,所以剛開(kāi)始定位問(wèn)題的思路出了點(diǎn)偏差,一直以為和安全加固操作有關(guān),所以尋找的資料也和Oracle相關(guān)。
根據(jù)網(wǎng)上的資料,在sqlnet.ora文件中定義SQLNET.INBOUND_CONNECT_TIMEOUT變量,經(jīng)過(guò)嘗試,設(shè)置為0或者一個(gè)比較大的值如30,都可以消除掉前述問(wèn)題。根據(jù)資料介紹,這個(gè)變量用來(lái)控制客戶端通過(guò)認(rèn)證的時(shí)間間隔,假如認(rèn)證時(shí)間超時(shí),則本次數(shù)據(jù)庫(kù)鏈接創(chuàng)建操作就會(huì)失敗,而縮短超時(shí)時(shí)間,可以有效的阻止DoS類(lèi)型的攻擊。根據(jù)安全加固操作指導(dǎo),加固操作確實(shí)包含用于修改認(rèn)證超時(shí)時(shí)間的指令。
問(wèn)題定位到這里,應(yīng)該說(shuō)找到了規(guī)避手段,也了解引發(fā)問(wèn)題的初因,但現(xiàn)場(chǎng)實(shí)施人員對(duì)于我的解釋并不滿意。好在我又找到一條新線索。
新線索
從Oracle官網(wǎng)論壇里找到一個(gè)帖子,討論的問(wèn)題和我遇到的問(wèn)題類(lèi)似,但提出的問(wèn)題原因和解決方法比較有意思。按照帖子里的說(shuō)法,問(wèn)題的根因和Java的安全隨機(jī)數(shù)生成器的實(shí)現(xiàn)原理相關(guān)。
java.security.SecureRandom is a standard API provided by sun. Among various methods offered by this class void nextBytes(byte[]) is one. This method is used for generating random bytes. Oracle 11g JDBC drivers use this API to generate random number during
login. Users using Linux have been encountering SQLException(“Io exception: Connection
reset”).The problem is two fold
- 1.The JVM tries to list all the files in the /tmp (or alternate tmp directory set by -Djava.io.tmpdir) when SecureRandom.nextBytes(byte[]) is invoked. If the number of files is large the method takes a long time to respond and hence cause the server to timeout
- 2.The method void nextBytes(byte[]) uses /dev/random on Linux and on some machines which lack the random number generating hardware the operation slows down to the extent of bringing the whole login process to a halt. Ultimately the the user encounters SQLException(“Io exception:
- Connection reset”)
Users upgrading to 11g can encounter this issue if the underlying OS is Linux which is running on a faulty hardware.
Cause
The cause of this has not yet been determined exactly. It could either be a problem in your hardware or the fact that for some reason the software cannot read from /dev/random
Solution
Change the setup for your application, so you add the next parameter to the java command:
-Djava.security.egd=file:///dev/urandom
現(xiàn)場(chǎng)實(shí)施人員對(duì)于這個(gè)帖子里的信息比較感興趣。按照帖子里的修改方法,在測(cè)試環(huán)境和生產(chǎn)環(huán)境做了多次驗(yàn)證,驚喜的發(fā)現(xiàn)問(wèn)題得到了解決。
隨機(jī)數(shù)生成器
如果不是為了解決問(wèn)題,平時(shí)也不會(huì)去刻意查閱底層實(shí)現(xiàn)相關(guān)的原理,這次是個(gè)好機(jī)會(huì)。網(wǎng)上關(guān)于/dev/random的介紹很多,只列出要點(diǎn):
- /dev/random是Linux內(nèi)核提供的安全隨機(jī)數(shù)生成設(shè)備;
- /dev/random依賴(lài)系統(tǒng)中斷信息來(lái)生成隨機(jī)數(shù),因而設(shè)備數(shù)目比較少時(shí),產(chǎn)生隨機(jī)數(shù)的速度比較慢,當(dāng)應(yīng)用對(duì)隨機(jī)數(shù)的需求比較大時(shí)會(huì)供不應(yīng)求;
- /dev/random在讀取時(shí)會(huì)阻塞調(diào)用線程;
- /dev/urandom是/dev/random的改良版本,解決了隨機(jī)數(shù)生成慢、阻塞調(diào)用的問(wèn)題,但同時(shí)稍微降低了安全性;
Linux環(huán)境下man random命令可以查閱到/dev/random和/dev/urandom的介紹,比較詳盡;
參考資料
https://community.oracle.com/message/3701989
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java獲取網(wǎng)絡(luò)文件并插入數(shù)據(jù)庫(kù)的代碼
抓取各大網(wǎng)站的數(shù)據(jù)插入數(shù)據(jù)庫(kù),這樣就不用為沒(méi)有數(shù)據(jù)而煩惱了2010-06-06
項(xiàng)目管理利器-Maven(Windows安裝)圖文教程
下面小編就為大家?guī)?lái)一篇項(xiàng)目管理利器-Maven(Windows安裝)圖文教程。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
MyBatis中#號(hào)與美元符號(hào)的區(qū)別
#{變量名}可以進(jìn)行預(yù)編譯、類(lèi)型匹配等操作,#{變量名}會(huì)轉(zhuǎn)化為jdbc的類(lèi)型。很多朋友不清楚在mybatis中#號(hào)與美元符號(hào)的不同,接下來(lái)通過(guò)本文給大家介紹兩者的區(qū)別,感興趣的朋友參考下吧2017-01-01
java IO流將一個(gè)文件拆分為多個(gè)子文件代碼示例
這篇文章主要介紹了java IO流將一個(gè)文件拆分為多個(gè)子文件代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
通過(guò)java備份恢復(fù)mysql數(shù)據(jù)庫(kù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了如何通過(guò)java備份恢復(fù)mysql數(shù)據(jù)庫(kù),其實(shí)一般情況下通過(guò)bat或sh就可以,這里主要是介紹了java的實(shí)現(xiàn)思路,喜歡的朋友可以參考下2013-09-09
Spring?Native打包本地鏡像的操作方法(無(wú)需通過(guò)Graal的maven插件buildtools)
這篇文章主要介紹了Spring?Native打包本地鏡像,無(wú)需通過(guò)Graal的maven插件buildtools,本文探索一下,如果不通過(guò)這個(gè)插件來(lái)生成鏡像,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
Java編程中使用JDBC API連接數(shù)據(jù)庫(kù)和創(chuàng)建程序的方法
這篇文章主要介紹了Java編程中使用JDBC API連接數(shù)據(jù)庫(kù)和創(chuàng)建程序的基本教程,JDBC是一種用于執(zhí)行SQL語(yǔ)句的Java API,可以為多種關(guān)系數(shù)據(jù)庫(kù)提供統(tǒng)一訪問(wèn)需要的朋友可以參考下2015-12-12
spring-boot-starter-parent的作用詳解
這篇文章主要介紹了spring-boot-starter-parent的作用詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08
Java利用PDFBox實(shí)現(xiàn)PDF文檔基本操作
這篇文章主要為大家詳細(xì)介紹了java如何利用PDFBox實(shí)現(xiàn)PDF文檔基本操作,例如創(chuàng)建PDF文檔、加載PDF文檔、獲取總頁(yè)數(shù)等,需要的小伙伴可以參考下2023-11-11

