1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Hive中文乱码(JDBC连接HiveServer2)问题解决

Hive中文乱码(JDBC连接HiveServer2)问题解决

时间:2020-05-07 11:23:53

相关推荐

Hive中文乱码(JDBC连接HiveServer2)问题解决

工作中遇到通过jdbc连接hive服务器(我们是用HiveServer2),获取的中文是乱码的问题。使用beeline有同样的效果,而用hive命令行却能正常显示中文。而写入,读取的文件,都是用的UTF-8,Java环境也都是UTF-8字符集。这是怎么回事?

问题重现

我们可以以如下方式重现:

shell> cat upload.txt

row1

行2

行3

row4

hive中在default库中创建表str_test(v string),然后将upload.txt文件上传到该表的存储路径:

shell> hadoop fs -put upload.txt /user/hive/warehouse/str_test/

shell> beeline -d org.apache.hive.jdbc.HiveDriver -u jdbc:hive2://localhost:10000 -e “select * from str_test”

+——-+

| v |

+——-+

| row1 |

| ?2 |

| ?3 |

| row4 |

| |

+——-+

shell> hive -e “select * from str_test”

row1

行2

行3

row4

出现乱码时,交互方式是:Client->jdbc->Hive Server2->Hadoop,而正常显示的Hive命令行的交互是:Hive CLI->Hadoop。所以基本可以确定乱码问题在Client->jdbc->Hive Server2这三个部分的其中一个部分上。

排查1.Client

Client是我们自行开发的Java应用,经查整个项目一直都是用的UTF-8字符集,排查Client的编码问题。

排查2.jdbc

网上查询一番类似的问题,参考了 文章1和2后,我们初步认为,采用网上推荐的方案,更新hive的JDBC驱动程序,将获取的字符强制硬编码使用UTF-8字符集,可以解决我们的问题。

我们使用的驱动包是hive-jdbc-0.10.0-cdh4.5.0.jar,可以看到里面有两个包:

我们按照网上的说法,更新org.apache.hadoop.hive.jdbc.HiveResultSet,采用如下patch:

Index: jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveQueryResultSet.java

===================================================================

— jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveQueryResultSet.java (revision 1195103)

+++ jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveQueryResultSet.java (working copy)

@@ -153,7 +153,7 @@

StructObjectInspector soi = (StructObjectInspector) serde.getObjectInspector();

List fieldRefs = soi.getAllStructFieldRefs();

- Object data = serde.deserialize(new BytesWritable(rowStr.getBytes()));

+ Object data = serde.deserialize(new BytesWritable(rowStr.getBytes(“UTF-8″)));

assert row.size() == fieldRefs.size() : row.size() + “, ” + fieldRefs.size();

for (int i = 0; i < fieldRefs.size(); i++) {

这个patch强制将获取的内容强制使用UTF-8编码解码。修改jar的方式是

获取jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveQueryResultSet.java的源码(通过svn:/repos/asf/hive/trunk或者使用Maven直接download source)在依赖满足的情况下编译获取class文件用新生成的HiveQueryResultSet.class直接替换掉hive-jdbc jar中org.apache.hadoop.hive.jdbc包下HiveQueryResultSet.class!

按照如上方式处理后,发现依然无效。不仅如此,我们调整LOG为DEBUG(即打印出大量DEBUG日志),然后尝试各种方法:加入打印语句、修改输出内容、甚至整个删除jar中的org.apache.hadoop.hive.jdbc包等等,最终发现,Java程序调用Hive JDBC时根本没进入org.apache.hadoop.hive.jdbc中,即使删除org.apache.hadoop.hive.jdbc这个包都没影响,生效的是org.apache.hive.jdbc包中的内容!

在org.apache.hive.jdbc包中没有找到相似的serde.deserialize这样的反序列化的语句。看来网上的方案在我们这不适用。那么这两个包是什么用途,什么关系呢?

从HiveServer2 Clients中,一段话提醒了我们:

The JDBC connection URL format has the prefix jdbc:hive2:// and the Driver class isorg.apache.hive.jdbc.HiveDriver. Note that this is different from the oldHiveServer.

再看第一版本的HiveServer Client,使用的是:

driverName = “org.apache.hadoop.hive.jdbc.HiveDriver“;

看到这两个包,在比对我们疑惑的两个包,一切明朗了:

org.apache.hadoop.hive.jdbc针对HiveServer1,与我们的场景无关。org.apache.hive.jdbc针对HiveServer2,我们需要关注。如上网络上给出的方案针对HiveServer1,确实不适用我们的场景。

细查org.apache.hive.jdbc的类,发现这个版本与HiveServer1的处理完全不一样了,不是使用serde,还是直接用了thrift,其中也没找到编码相关的选项。这条路走到头了。

排查3.HiveServer2

剩下就是检查HiveServer2使用的字符集了。

系统层面:

shell> locale

LANG=zh_CN.UTF-8

LC_CTYPE=”zh_CN.UTF-8″

LC_NUMERIC=”zh_CN.UTF-8″

LC_TIME=”zh_CN.UTF-8″

LC_COLLATE=”zh_CN.UTF-8″

LC_MONETARY=”zh_CN.UTF-8″

LC_MESSAGES=”zh_CN.UTF-8″

LC_PAPER=”zh_CN.UTF-8″

LC_NAME=”zh_CN.UTF-8″

LC_ADDRESS=”zh_CN.UTF-8″

LC_TELEPHONE=”zh_CN.UTF-8″

LC_MEASUREMENT=”zh_CN.UTF-8″

LC_IDENTIFICATION=”zh_CN.UTF-8″

LC_ALL=

shell> echo $LANG

zh_CN.UTF-8

我们是使用CDH4.5中自带的hive-server2启动脚本启动的hiveserver2服务,看看脚本环境中字符集是怎样的。

/etc/init.d/hive-server2中添加locale命令,重启后却是这样的:

shell> service hive-server2 restart

LANG=

LC_CTYPE=”POSIX”

LC_NUMERIC=”POSIX”

LC_TIME=”POSIX”

LC_COLLATE=”POSIX”

LC_MONETARY=”POSIX”

LC_MESSAGES=”POSIX”

LC_PAPER=”POSIX”

LC_NAME=”POSIX”

LC_ADDRESS=”POSIX”

LC_TELEPHONE=”POSIX”

LC_MEASUREMENT=”POSIX”

LC_IDENTIFICATION=”POSIX”

LC_ALL=

Starting Hive Server2 (hive-server2): [确定]

Hive Server2 is running [确定]

看来hive-server2的运行环境并没有沿用系统层面的环境,针对它进行配置:

在/etc/init.d/hive-server2删除刚添加的locale,然后添加语句:export LANG=zh_CN.UTF-8

这样确保hive-server2的启动会使用指定字符集。

当然,如果使用hive –service hiveserver2命令启动,只要保证环境变量LANG=zh_CN.UTF-8即可。

测试结果,如上设置,重启hive-server2后,乱码问题解决!

小结

最终解决乱码问题只是添加了export LANG=zh_CN.UTF-8,确保hive-server2的运行环境使用的是UTF-8字符集,这样Client,Hive-Server和Hadoop集群都采用了UTF-8,自然不会有乱码存在了。

Done!

参考:

http://wocclyl./blog/static/462235044301120474/

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。