1. 程式人生 > >oracle常見異常——io異常,connection reset

oracle常見異常——io異常,connection reset

解決方案

java -jar -Djava.security.egd=file:/dev/../dev/urandom xxx.jar

詳述

從Oracle官網論壇裡找到一個帖子,討論的問題和我遇到的問題類似,但提出的問題原因和解決方法比較有意思。按照帖子裡的說法,問題的根因和Java的安全隨機數生成器的實現原理相關。

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.

CauseThe 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

SolutionChange the setup for your application, so you add the next parameter to the java command:

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

現場實施人員對於這個帖子裡的資訊比較感興趣。另外在測試環境經過多次重試,順利復現問題併成功的提取到了發生問題時的呼叫棧。分析測試環境裡提取到的棧檔案,發現和上述帖子裡描述的呼叫過程非常近似,說明帖子裡方法很有希望解決我遇到的問題。因而按照帖子裡的修改方法,在測試環境和生產環境做了多次驗證,驚喜的發現問題得到了解決。

最終的解決方法

修改應用的JVM引數,方法找到有如下幾種:

-Djava.security.egd=file:/dev/../dev/urandom
-Djava.security.egd=file:/dev/./urandom
-Djava.security.egd=file:/dev/urandom #據說這種方法有Bug,沒有做進一步的驗證;也沒有查閱過程式碼,所以不瞭解問題在哪。
後來查閱其它資料時發現,原來JRE的java.security檔案對變數java.security.egd早有定義。

#
# Select the source of seed data for SecureRandom. By default an
# attempt is made to use the entropy gathering device specified by
# the securerandom.source property. If an exception occurs when
# accessing the URL then the traditional system/thread activity
# algorithm is used.
#
# On Solaris and Linux systems, if file:/dev/urandom is specified and it
# exists, a special SecureRandom implementation is activated by default.
# This “NativePRNG” reads random bytes directly from /dev/urandom.
#
# On Windows systems, the URLs file:/dev/random and file:/dev/urandom
# enables use of the Microsoft CryptoAPI seed functionality.
#
securerandom.source=file:/dev/urandom
#
# The entropy gathering device is described as a URL and can also
# be specified with the system property “java.security.egd”. For example,
# -Djava.security.egd=file:/dev/urandom
# Specifying this system property will override the securerandom.source
# setting.

隨機數生成器

如果不是為了解決問題,平時也不會去刻意查閱底層實現相關的原理,這次是個好機會。網上關於/dev/random的介紹很多,只列出要點:

1)/dev/random是Linux核心提供的安全隨機數生成裝置;

2)/dev/random依賴系統中斷資訊來生成隨機數,當裝置數目比較少時,產生隨機數的速度比較慢,如果應用對隨機數的需求比較大時就會供不應求;

3)/dev/random在讀取時會阻塞呼叫執行緒;

4)/dev/urandom是/dev/random的改良版本,解決了隨機數生成慢、阻塞呼叫的問題,但同時稍微降低了安全性;

5)Linux環境下man random命令可以查閱到/dev/random和/dev/urandom的介紹,比較詳盡;

參考資料