背景
由於我們公司使用了biee給業務方同學查詢數據,很多時候需要在hive計算結果后,導入到oracle中。但是在數據量特別大的時候,經常會出現:
Caused by: java.io.IOException: java.sql.SQLException: 關閉的連接
查看MR日志,可以發現其中有一段Connection Reset,然后sqoop任務就會重試,可以從日志中看到,重試並不是無縫的,那么就必然會導致一部分數據double(猜想重試應該是task級別的,也就是這個map task失敗后,重試整個map task,但是這個map的部分數據已經寫入了數據庫,猜想sqoop導出其實就是一堆insert into value,因為你可以發現任務在跑的時候,數據庫中表的數據是慢慢增加的)。
問題追蹤
sqoop導出任務可以配置update-key,但是部分表缺乏主鍵。或者加入這個字段會影響效率。在經過查詢后,發現一個非常好的解釋:http://stackoverflow.com/questions/2327220/oracle-jdbc-intermittent-connection-issue/,大致可以這么理解Oracle JDBC在和Oracle server連接時,是通過一種安全的方式。驅動使用的是java.security.SecureRandom
SecureRandom random = new SecureRandom(); byte bytes[] = new byte[20]; random.nextBytes(bytes);
調用者也可以調用generateseed方法來獲取一個
byte seed[] = random.generateSeed(20);
同時,這里面有一條備注:
Note: Depending on the implementation, the generateSeed
and nextBytes
methods may block as entropy is being gathered, for example, if they need to read from /dev/random on various unix-like operating systems.
在Oracle JDBC中,就是通過獲取entropy來安全的連接。
Entropy(熵)是由需要隨機數或者密碼學的操作系統或者應用程序收集/生成的隨機性。這種隨機性可以通過硬件來源,或者其他硬件噪音,多媒體數據,鼠標移動或者特定的提供隨機性的生成器。內核收集entropy並將他們存儲在一個entropy pool中。並使這部分隨機字節數據可以被操作系統或者應用訪問,通過特定的文件/dev/random 和/dev/urandom
從/dev/random讀取以所請求的位/字節數量,排出熵池。從而提供密碼操作中需要的高度隨機性。在entropy pool 完全耗盡,並且沒有足夠的熵可用的情況下。會對/dev/random的讀操作阻塞,直到收集到額外的熵。因此,從/dev/random讀取的應用程序可能會阻塞一段隨機時間。
相反的是,從/dev/urandom讀取不會阻塞。從/dev/urandom讀取也需要熵池,但是當缺乏足夠的熵時,它不會阻塞,而是重新使用來自部分隨機數據的位。據說容易受到密碼分析攻擊,因此不鼓勵從/dev/urandom讀取加密操作中需要的隨機性。
java.security.SecureRandom類默認從/dev/random文件讀取,因此有時會阻塞隨機時間段。現在,如果讀取操作沒有返回所需的時間量,Oracle服務器會超時客戶端(JDBC driver),並關閉末尾的套接字來刪除通信。客戶端(JDBC Driver)從阻塞調用返回嘗試恢復通信會遇到IO異常。
解決方法
在如果從/dev/random讀取阻塞,我們就讓它從/dev/urandom讀取,即加入參數sqoop export -D mapred.child.java.opts="\-Djava.security.egd=/dev/urandom"