最近数据中台同步中心的同学反馈mysql同步至hive任务偶尔发生java.net.SocketTimeoutException: Read timed out
异常,排查后发hive-jdbc的使用现有点坑。
先说结论
在jdbc中timeout参数是静态全局变量,多种数据源jdbc存在时,timeout参数的设置之间存在干扰。
背景
我们数据中台的同步中心模块提供了异构数据源之间的数据流转服务,底层部分功能是基于阿里开源DataX(https://github.com/alibaba/DataX)的二次开发实现。出现问题的模块是`Mysql2Hive`,异常栈如下:
1 | 2021-03-30 10:37:31.527 [job-0] WARN HiveClient - fail to close hive res. |
排查经过
这里有两个异常:
异常一:org.apache.thrift.TApplicationException: CloseOperation failed: out of sequence response
异常二:java.net.SocketTimeoutException: Read timed out
一开始,认定是server端异常导致。即hiveserver2端发生了异常,从而导致jdbc客户端侧异常。经过详细排查hiveserver2的日志,并没有发现可疑点,这似乎走进了死胡同,一时不知从何查起。过了几天,中台同学反馈有更多任务报错。随即我们对这个问题提高了优先级。经过冷静分析,任何代码都是程序员写的,任何异常都有根可循,异常还是得从异常栈分析。
CloseOperation failed: out of sequence response
跟踪第一个异常的栈信息我们发现是在执行close操作,结合Hive源码分析可知,这里是连接已经失败,也就是说它是结果,根因并不是它。这里特别容易产生误导。
java.net.SocketTimeoutException: Read timed out
这里才是主因。首先异常抛出点是个Native Method
,我们一起来看看,在java.net包中,定位到源码如下:
1 | /** |
可知,该方法有个参数timeout,于是乎,我们去查找这个timeout从何而来:
1 | /** |
继续追踪,发现超时时间来自于SO_TIMEOUT
:
1 | abstract class AbstractPlainSocketImpl extends SocketImpl |
它的赋值在下面方法中:
1 | public void setOption(int opt, Object val) throws SocketException { |
谁调用呢?
从下图可知,该参数完全可以在客户端进行设置,原理和mysql的jdbc超时时间类似。
真的是这个参数原因吗?
我们写个 socket demo 验证下:
Server端:
1 | package socket; |
Client端:
1 | package socket; |
成功复现:
由此可见,显然是客户端进行了设置。但排查用户代码发现,并没有相关设置代码。
难道是HIVE自身设置的TIMEOUT?
仔细跟踪hive-jdbc相关代码,我们发现的确是hive设置的loginTimeout
:
1 | /** |
可知timeOut取自DriverManager.getLoginTimeout()
,而这个参数是全局共享变量,源码如下:
1 | public class DriverManager { |
也就是说如果存在多个jdbc源,此时会相互影响。比如mysql-jdbc设置超时时间15,此时hive-jdbc希望timeout是0(永不超时),但此时会拿到mysql的超时时间。
解决方案
这就有点坑了,怎么办呢?
第一个方案,在用户层创建jdbc连接时,重置timeout为0:
1 | DriverManager.setLoginTimeout(0); |
第二个方案在hive源码侧进行修改,这个社区已经在2月份最新版的hive中进行了修复:
HIVE-12371: Adding a timeout connection parameter for JDBC
可以backport该patch到自己版本的hive-jdbc中修复该问题。
本文链接: https://stefanxiepj.github.io/archives/7d9ae77b.html
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!
![知识共享许可协议](https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png)