虽然已经很习惯看静态代码了,但是这种方式始终很不方便,需要来来回回翻找代码不说,还得自己分析每个变量的值、和路径。因此决定花点时间让代码在IDE上跑起来,然而这个过程在Windows
下十分麻烦。
你是否正在尝试,或是多次尝试失败在
windows
下调试Hive呢?本文将从零重现笔者在搭建hive在windows下运行环境的出现的问题。带你解决本地调试的各种问题、各种坑,直接吃鸡。
一、准备
开始之前先重申一下我们的目的,我们的目的是让hive在IDE(windows)上跑起来。
- 如果你是mac/linux的话,相对简单一些。可以省去成吨的操作,至少我用ubuntu弄的话就很简单。
其实,如你所以Hive依赖Hadoop的MapReduce或者tez、Spark计算引擎完成计算的,那么毕竟离不到Hadoop。
但其实你可以不需要把hadoop的环境搭起来,只要把它的发行包解压,并能让hive找到hadoop.cmd即可。
此时我们有多种方式去实现,简单可以有如下两种,对这两种我们都简单介绍一下。
1. 下载源码,导入IDE
1. 下载Apache发行码
2. 从github clone
2. 建个项目,把包引进来
在hive-0.13.0
以后,Hive的构建工具从Ant
迁移到Maven
。那不管你是下载Apache发行版本的源码包,还是从github克隆源码都是一样的,下载了之后最好能在CMD
下完成构建。即是在CMD
下完成如下操作将源码转成eclipse/idea项目
- 对于Eclipse
mvn eclipse:eclipse -Phadoop-2
- 对于Intellj
mvn idea:idea -Phadoop-2
当然,你也可以通过maven
直接导入成一个maven项目
。
然后如果你觉得这也是挺麻烦的,那还可以直接在任意一个maven项目
中引入Hive
相关的包,通过相关提示加入必要的包即可。比如org.apache.hadoop:hadoop-minicluster
。
好了,不管你选择哪种最终都会遇到以下提及的所有问题。
那我们知道把Hive的CliDriver在本地跑起来,当然需要把配置为Local
模式,按官方Wiki文档的说明配置即可。只不过,我们要做的远不仅仅如此。
export HIVE_OPTS=’–hiveconf mapred.job.tracker=local –hiveconf fs.default.name=file:///tmp \
–hiveconf hive.metastore.warehouse.dir=file:///tmp/warehouse \
–hiveconf javax.jdo.option.ConnectionURL=jdbc:derby:;databaseName=/tmp/metastore_db;create=true’
二、事情远没这么简单呢
如果,按着WIKI文档说的做一些配置即可的话,那我也不必写这篇文章了啦。其实问题还挺多的,接下来我会按着问题发生的顺序,一步步的解决,并把每个问题报错提示和我的解决方案一起贴出来。
2.1 winutils.exe找不到
首先是这个:
ERROR util.Shell: Failed to locate the winutils binary in the hadoop binary path
java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.
Exception in thread "main" java.lang.RuntimeException: java.lang.NullPointerException
at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java:522)
at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java:466)
Caused by: java.lang.NullPointerException
at java.lang.ProcessBuilder.start(Unknown Source)
at org.apache.hadoop.util.Shell.runCommand(Shell.java:483)
找不到winutils.exe
,这个谷歌一下就能很容易得知了。详细见这里。一开始我并没有在意找不到winutils.exe
的问题,而是先去找下面那个NullPointerException
的问题。然后发现这里的问题是需要执行中,少了一个hadoopCMD
。跟在它后面是ls -la /tmp/hive
,然后我大概就能懂了。原来winutils.exe
真心不是随便能不要的,到这里下载winutils.exe
。然后把对应hadoop版本的winutils拿出来并把配置系统变量Path上。
2.2 系统找不到指定的文件
并在启动时加入如下参数,(当然你也能把它直接写到hive-site.xml
的配置文件上)
-Dhadoop.home.dir=D:\hadoop-2.7.5\
java.io.IOException: Cannot run program "\usr\bin\hadoop.cmd" (in directory "D:\daming\workspace\hive"): CreateProcess error=2, 系统找不到指定的文件。
at java.lang.ProcessBuilder.start(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at org.apache.hadoop.hive.ql.exec.mr.MapRedTask.execute(MapRedTask.java:271)
at org.apache.hadoop.hive.ql.exec.Task.executeTask(Task.java:160)
at org.apache.hadoop.hive.ql.exec.TaskRunner.runSequential(TaskRunner.java:88)
at org.apache.hadoop.hive.ql.Driver.launchTask(Driver.java:1653)
at org.apache.hadoop.hive.ql.Driver.execute(Driver.java:1412)
at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:1195)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1059)
at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1049)
at com.watsons.hive.SemanticAnalyzerTest.main(SemanticAnalyzerTest.java:49)
Caused by: java.io.IOException: CreateProcess error=2, 系统找不到指定的文件。
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.<init>(Unknown Source)
at java.lang.ProcessImpl.start(Unknown Source)
... 12 more
由于它是从HiveConf里拿hadoop.bin.path
,我们知道HiveConf会读入几个配置,除了各种XML(hive-site.xml, core-site.xml,…),还整合了System.getProperty
和System.getEnv
。所以你除了可以在hive-site.xml加入如下配置项,也可以直接加个JVM参数-Dhadoop.bin.path=
。
<property>
<name>hadoop.bin.path</name>
<value>D:/hadoop-2.7.5/bin/hadoop.cmd</value>
</property>
2.3 系统找不到指定的路径
到这里你以为就可以了,毕竟只是提示你找不到表而已,那大不了建个表呗。嗯,建表没问题。一直到有一天,你的SQL需要发起一个MapReduce任务了。然后它立马跟你说,找不到JAVA_HOME
,此时我想你的内心立马就不能平静了。
系统找不到指定的路径。
Error: JAVA_HOME is incorrectly set.
Please update D:\hadoop-2.7.5\conf\hadoop-env.cmd
'-Xmx512m' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
WHAT!!!什么情况,JAVA_HOME
,找不到吗?没JAVA_HOME,你说我是怎么运行各种各样的JavaApp呢?你可能按着它说的,在$HADOOP_HOME/conf/
创建这个目录,并创建这个文件hadoop-env.cmd
,把set JAVA_HOME=%JAVA_HOME%
写进去。但是但是,它依然还是不行,哈哈哈。其实这个问题很容易被忽略而已,因为当你把java装在c:\Program Files
时,它有个空格且没能被识别。如果是这样的话,把Java
拷到一个地方即可。D:\java.tools\java
,然后再hadoop-env.cmd
把上面那句话改成set JAVA_HOME=D:\java.tools\java\jdk1.8.0_121
。
三、这样就可以了吗?
到这里,你以为就可以了吗?默默的看了一下进度条,答案很清晰,并没有。
3.1 UnsatisfiedLinkError
接下来是这个问题了:
java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z
...
FAILED: Execution Error, return code -101 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask. org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z
一开始没看出来这是什么问题,谷歌也很茫然。
后来我在TestCliDriver
里看两行代码,才把这个问题解决了的。
HiveConf conf = new HiveConf(ExecDriver.class);
conf.setBoolVar(HiveConf.ConfVars.SUBMITVIACHILD, true);
conf.setBoolVar(HiveConf.ConfVars.SUBMITLOCALTASKVIACHILD, true);
直接这个hive-site.xml
里加如下两项配置即可:
<property>
<name>hive.exec.submitviachild</name>
<value>true</value>
</property>
<property>
<name>hive.exec.submit.local.task.via.child</name>
<value>true</value>
</property>
3.2 如果还不行
那可能是提示它需要的目录权限不足,执行winutils chmod -R 777 d:/tmp/
完成即可。
这要是还有问题的话,那也是我没到遇到的,请文章的评论区直接评论,我们一起来探讨咯。
四、结尾
到这里的话,其实已经完成搞定了。但总觉得日志打印有点问题,如果你也是这么觉得的话,加入这个JVM参数。-Dhive.root.logger=INFO,console
,当然你可能按你的需求打到对应的日志级别即可了。
最后我还是觉得通过CliDriver
的方式,还是有点慢。那么其实你可能直接写代码,直接操作Driver
即可。
- 这个过程中需要你做一些准备
- 如果本地没有hadoop环境,需要下载hadoop发行包,并解压。
- 需要安装 winutils.exe,hadoop在windows运行环境。
- hive-site.xml
最后的最后,把hive-site.xml文件完整的贴出来吧。
<configuration>
<property>
<name>mapred.job.tracker</name>
<value>local</value>
</property>
<property>
<name>fs.default.name</name>
<value>file:///d:/tmp</value>
</property>
<property>
<name>hive.metastore.warehouse.dir</name>
<value>file:///d:/tmp/warehouse</value>
</property>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:derby:;databaseName=d:/tmp/metastore_db;create=true</value>
</property>
<property>
<name>datanucleus.autoCreateTables</name>
<value>True</value>
</property>
<property>
<name>hadoop.bin.path</name>
<value>D:/hadoop-2.7.5/bin/hadoop.cmd</value>
</property>
<property>
<name>hive.exec.submitviachild</name>
<value>true</value>
</property>
<property>
<name>hive.exec.submit.local.task.via.child</name>
<value>true</value>
</property>
</configuration>