背景
由于我们公司使用了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"