1. 程式人生 > >Hive本地除錯

Hive本地除錯

雖然已經很習慣看靜態程式碼了,但是這種方式始終很不方便,需要來來回回翻找程式碼不說,還得自己分析每個變數的值、和路徑。因此決定花點時間讓程式碼在IDE上跑起來,然而這個過程在Windows

下十分麻煩。

你是否正在嘗試,或是多次嘗試失敗在windows除錯Hive呢?本文將從零重現筆者在搭建hive在windows下執行環境的出現的問題。帶你解決本地除錯的各種問題、各種坑,直接吃雞。

一、準備

開始之前先重申一下我們的目的,我們的目的是讓hive在IDE(windows)上跑起來。

  1. 如果你是mac/linux的話,相對簡單一些。可以省去成噸的操作,至少我用ubuntu弄的話就很簡單。
  2. 其實,如你所以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.getPropertySystem.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即可。

  • 這個過程中需要你做一些準備
    1. 如果本地沒有hadoop環境,需要下載hadoop發行包,並解壓。
    2. 需要安裝 winutils.exe,hadoop在windows執行環境。
    3. 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>