前提
筆者目前需要搭建資料平臺,發現了Windows
系統下,Hadoop
和Hive
等元件的安裝和執行存在大量的坑,而本著有坑必填的目標,筆者還是花了幾個晚上的下班時候在多個網際網路參考資料的幫助下完成了Windows10
系統下Hadoop
和Hive
開發環境的搭建。這篇文章記錄了整個搭建過程中的具體步驟、遇到的問題和對應的解決方案。
環境準備
基於筆者的軟體版本潔癖,所有選用的元件都會使用當前(2020-10-30)最高的版本。
軟體 | 版本 | 備註 |
---|---|---|
Windows |
10 |
作業系統 |
JDK |
8 |
暫時不要選用大於等於JDK9 的版本,因為啟動虛擬機器會發生未知異常 |
MySQL |
8.x |
用於管理Hive 的後設資料 |
Apache Hadoop |
3.3.0 |
- |
Apache Hive |
3.1.2 |
- |
Apache Hive src |
1.2.2 |
因為只有1.x 版本的Hive 原始碼提供了.bat 啟動指令碼,有能力可以自己寫指令碼就不用下此原始碼包 |
winutils |
hadoop-3.3.0 |
Hadoop 的Windows 系統下的啟動依賴 |
下面列舉部分元件對應的下載地址:
Apache Hadoop 3.3.0
:https://mirror.bit.edu.cn/apache/hadoop/common/hadoop-3.3.0/hadoop-3.3.0.tar.gz
Apache Hive 3.1.2
:https://mirrors.bfsu.edu.cn/apache/hive/hive-3.1.2/apache-hive-3.1.2-bin.tar.gz
Apache Hive 1.2.2 src
:https://mirrors.bfsu.edu.cn/apache/hive/hive-1.2.2/apache-hive-1.2.2-src.tar.gz
winutils
:https://github.com/kontext-tech/winutils
(如果下載速度慢,可以先把倉庫匯入gitee.com
再下載,或者用筆者已經同步好的倉庫https://gitee.com/throwableDoge/winutils
)
下載完這一些列軟體之後,MySQL
正常安裝為系統服務隨系統自啟。解壓hadoop-3.3.0.tar.gz
、apache-hive-3.1.2-bin.tar.gz
、apache-hive-1.2.2-src.tar.gz
和winutils
到指定目錄:
接著把原始碼包apache-hive-1.2.2-src.tar.gz
解壓後的bin
目錄下的檔案拷貝到apache-hive-3.1.2-bin
的bin
目錄中:
然後把winutils
中的hadoop-3.3.0\bin
目錄下的hadoop.dll
和winutils.exe
檔案拷貝到Hadoop
的解壓目錄的bin
資料夾下:
最後再配置一下JAVA_HOME
和HADOOP_HOME
兩個環境變數,並且在Path
中新增%JAVA_HOME%\bin;
和%HADOOP_HOME%\bin
:
筆者本地安裝的JDK版本為1.8.0.212,理論上任意一個小版本的JDK8都可以。
接著用命令列測試一下,如果上述步驟沒問題,控制檯輸出如下:
配置和啟動Hadoop
在HADOOP_HOME
的etc\hadoop
子目錄下,找到並且修改下面的幾個配置檔案:
core-site.xml(這裡的tmp
目錄一定要配置一個非虛擬目錄,別用預設的tmp
目錄,否則後面會遇到許可權分配失敗的問題)
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/e:/LittleData/hadoop-3.3.0/data/tmp</value>
</property>
</configuration>
hdfs-site.xml(這裡要預先建立nameNode
和dataNode
的資料存放目錄,注意一下每個目錄要以/
開頭,筆者這裡預先在HADOOP_HOME/data
建立了nameNode
和dataNode
子目錄)
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.http.address</name>
<value>0.0.0.0:50070</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/e:/LittleData/hadoop-3.3.0/data/nameNode</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/e:/LittleData/hadoop-3.3.0/data/dataNode</value>
</property>
<property>
<name>dfs.permissions.enabled</name>
<value>false</value>
</property>
</configuration>
mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
yarn-site.xml
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
<value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
</configuration>
至此,最小化配置基本完成。接著需要格式化namenode
並且啟動Hadoop
服務。切換至$HADOOP_HOME/bin
目錄下,使用CMD
輸入命令hdfs namenode -format
(格式化namenode
切記不要重複執行):
格式化namenode
完畢後,切換至$HADOOP_HOME/sbin
目錄下,執行start-all.cmd
指令碼:
這裡命令列會提示start-all.cmd
指令碼已經過期,建議使用start-dfs.cmd
和start-yarn.cmd
替代。同理,如果執行stop-all.cmd
也會有類似的提示,可以使用stop-dfs.cmd
和stop-yarn.cmd
替代。start-all.cmd
成功執行後,會拉起四個JVM
例項(見上圖中的Shell
視窗自動新建了四個Tab
),此時可以通過jps
檢視當前的JVM
例項:
λ jps
19408 ResourceManager
16324 NodeManager
14792 Jps
15004 NameNode
2252 DataNode
可見已經啟動了ResourceManager
、NodeManager
、NameNode
和DataNode
四個應用,至此Hadoop
的單機版已經啟動成功。通過stop-all.cmd
命令退出這四個程式。可以通過http://localhost:8088/
檢視排程任務的狀態:
通過http://localhost:50070/
去檢視HDFS
的狀態和檔案:
重啟Hadoop
的辦法:先執行stop-all.cmd
指令碼,再執行start-all.cmd
指令碼。
配置和啟動Hive
Hive
是構築於HDFS
上的,所以務必確保Hadoop
已經啟動。Hive
在HDFS
中預設的檔案路徑字首是/user/hive/warehouse
,因此可以先通過命令列在HDFS
中建立此資料夾:
hdfs dfs -mkdir /user/hive/warehouse
hdfs dfs -chmod -R 777 /user/hive/warehouse
同時需要通過下面的命令建立併為tmp
目錄賦予許可權:
hdfs dfs -mkdir /tmp
hdfs dfs -chmod -R 777 /tmp
在系統變數中新增HIVE_HOME
,具體的值配置為E:\LittleData\apache-hive-3.1.2-bin
,同時在Path
變數新增%HIVE_HOME%\bin;
,跟之前配置HADOOP_HOME
差不多。下載和拷貝一個mysql-connector-java-8.0.x.jar
到$HIVE_HOME/lib
目錄下:
建立Hive
的配置檔案,在$HIVE_HOME/conf
目錄下已經有對應的配置檔案模板,需要拷貝和重新命名,具體如下:
$HIVE_HOME/conf/hive-default.xml.template
=>$HIVE_HOME/conf/hive-site.xml
$HIVE_HOME/conf/hive-env.sh.template
=>$HIVE_HOME/conf/hive-env.sh
$HIVE_HOME/conf/hive-exec-log4j.properties.template
=>$HIVE_HOME/conf/hive-exec-log4j.properties
$HIVE_HOME/conf/hive-log4j.properties.template
=>$HIVE_HOME/conf/hive-log4j.properties
修改hive-env.sh
指令碼,在尾部新增下面內容:
export HADOOP_HOME=E:\LittleData\hadoop-3.3.0
export HIVE_CONF_DIR=E:\LittleData\apache-hive-3.1.2-bin\conf
export HIVE_AUX_JARS_PATH=E:\LittleData\apache-hive-3.1.2-bin\lib
修改hive-site.xml
檔案,主要修改下面的屬性項:
屬性名 | 屬性值 | 備註 |
---|---|---|
hive.metastore.warehouse.dir |
/user/hive/warehouse |
Hive 的資料儲存目錄,這個是預設值 |
hive.exec.scratchdir |
/tmp/hive |
Hive 的臨時資料目錄,這個是預設值 |
javax.jdo.option.ConnectionURL |
jdbc:mysql://localhost:3306/hive?characterEncoding=UTF-8&serverTimezone=UTC |
Hive 後設資料存放的資料庫連線 |
javax.jdo.option.ConnectionDriverName |
com.mysql.cj.jdbc.Driver |
Hive 後設資料存放的資料庫驅動 |
javax.jdo.option.ConnectionUserName |
root |
Hive 後設資料存放的資料庫使用者 |
javax.jdo.option.ConnectionPassword |
root |
Hive 後設資料存放的資料庫密碼 |
hive.exec.local.scratchdir |
E:/LittleData/apache-hive-3.1.2-bin/data/scratchDir |
建立本地目錄$HIVE_HOME/data/scratchDir |
hive.downloaded.resources.dir |
E:/LittleData/apache-hive-3.1.2-bin/data/resourcesDir |
建立本地目錄$HIVE_HOME/data/resourcesDir |
hive.querylog.location |
E:/LittleData/apache-hive-3.1.2-bin/data/querylogDir |
建立本地目錄$HIVE_HOME/data/querylogDir |
hive.server2.logging.operation.log.location |
E:/LittleData/apache-hive-3.1.2-bin/data/operationDir |
建立本地目錄$HIVE_HOME/data/operationDir |
datanucleus.autoCreateSchema |
true |
可選 |
datanucleus.autoCreateTables |
true |
可選 |
datanucleus.autoCreateColumns |
true |
可選 |
hive.metastore.schema.verification |
false |
可選 |
修改完畢之後,在本地的MySQL
服務新建一個資料庫hive
,編碼和字符集可以選用範圍比較大的utf8mb4
(雖然官方建議是latin1
,但是字符集往大範圍選沒有影響):
上面的準備工作做完之後,可以進行Hive
的後設資料庫初始化,在$HIVE_HOME/bin
目錄下執行下面的指令碼:
hive --service schematool -dbType mysql -initSchema
這裡有個小坑,hive-site.xml
檔案的第3215
行有個神奇的無法識別的符號:
此無法識別符號會導致Hive
的命令執行異常,需要去掉。當控制檯輸出Initialization script completed schemaTool completed
的時候,說明後設資料庫已經初始化完畢:
在$HIVE_HOME/bin
目錄下,通過hive.cmd
可以連線Hive
(關閉控制檯即可退出):
> hive.cmd
嘗試建立一個表t_test
:
hive> create table t_test(id INT,name string);
hive> show tables;
檢視http://localhost:50070/
確認t_test
表已經建立成功。
嘗試執行一個寫入語句和查詢語句:
hive> insert into t_test(id,name) values(1,'throwx');
hive> select * from t_test;
寫用了30
多秒,讀用了0.165
秒。
使用JDBC連線Hive
HiveServer2
是Hive
服務端介面模組,必須啟動此模組,遠端客戶端才能對Hive
進行資料寫入和查詢。目前,此模組還是基於Thrift RPC
實現,它是HiveServer
的改進版,支援多客戶端接入和身份驗證等功能。配置檔案hive-site.xml
中可以修改下面幾個關於HiveServer2
的常用屬性:
屬性名 | 屬性值 | 備註 |
---|---|---|
hive.server2.thrift.min.worker.threads |
5 |
最小工作執行緒數,預設值為5 |
hive.server2.thrift.max.worker.threads |
500 |
最大工作執行緒數,預設值為500 |
hive.server2.thrift.port |
10000 |
偵聽的TCP 埠號,預設值為10000 |
hive.server2.thrift.bind.host |
127.0.0.1 |
繫結的主機,預設值為127.0.0.1 |
hive.execution.engine |
mr |
執行引擎,預設值為mr |
在$HIVE_HOME/bin
目錄下執行下面的命令可以啟動HiveServer2
:
hive.cmd --service hiveserver2
客戶端需要引入hadoop-common
和hive-jdbc
依賴,依賴的版本儘量和對接的Hadoop
和Hive
版本對應。
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>
hadoop-common
依賴鏈比較長,會連帶下載大量其他相關依賴,所以可以找個空閒時間在某個Maven
專案先掛起該依賴下載的任務(筆者掛起此依賴下載任務洗完澡仍然沒下完,還會出現org.glassfish:javax.el
的快照包無法下載的問題,不過不影響正常使用)。最後新增一個單元測試類HiveJdbcTest
:
@Slf4j
public class HiveJdbcTest {
private static JdbcTemplate TEMPLATE;
private static HikariDataSource DS;
@BeforeClass
public static void beforeClass() throws Exception {
HikariConfig config = new HikariConfig();
config.setDriverClassName("org.apache.hive.jdbc.HiveDriver");
// 這裡筆者修改過hive-site.xml的對應配置,因為埠不是預設的10000
// config.setJdbcUrl("jdbc:hive2://127.0.0.1:10091");
config.setJdbcUrl("jdbc:hive2://127.0.0.1:10091/db_test");
DS = new HikariDataSource(config);
TEMPLATE = new JdbcTemplate(DS);
}
@AfterClass
public static void afterClass() throws Exception {
DS.close();
}
@Test
public void testCreateDb() throws Exception {
TEMPLATE.execute("CREATE DATABASE db_test");
}
@Test
public void testCreateTable() throws Exception {
TEMPLATE.execute("CREATE TABLE IF NOT EXISTS t_student(id INT,name string,major string)");
log.info("建立t_student表成功");
}
@Test
public void testInsert() throws Exception {
int update = TEMPLATE.update("INSERT INTO TABLE t_student(id,name,major) VALUES(?,?,?)", p -> {
p.setInt(1, 10087);
p.setString(2, "throwable");
p.setString(3, "math");
});
log.info("寫入t_student成功,更新記錄數:{}", update); // 這裡比較神奇,資料寫入了,返回的update數量為0
}
@Test
public void testSelect() throws Exception {
List<Student> result = TEMPLATE.query("SELECT * FROM t_student", rs -> {
List<Student> list = new ArrayList<>();
while (rs.next()) {
Student student = new Student();
student.setId(rs.getLong("id"));
student.setName(rs.getString("name"));
student.setMajor(rs.getString("major"));
list.add(student);
}
return list;
});
// 列印日誌:查詢t_student成功,結果:[HiveJdbcTest.Student(id=10087, name=throwable, major=math)]
log.info("查詢t_student成功,結果:{}", result);
}
@Data
private static class Student {
private Long id;
private String name;
private String major;
}
}
可能遇到的問題
下面小結一下可能遇到的問題。
Java虛擬機器啟動失敗
目前定位到是Hadoop
無法使用JDK[9+
的任意版本JDK
,建議切換為任意JDK8
的小版本。
出現找不到Hadoop執行檔案異常
確保已經把winutils
中的hadoop-3.3.0\bin
目錄下的hadoop.dll
和winutils.exe
檔案拷貝到Hadoop
的解壓目錄的bin
資料夾中。
start-all.cmd
指令碼執行時有可能出現找不到批處理指令碼的異常。此問題在公司的開發機出現過,在家用的開發機沒有重現,具體解決方案是在start-all.cmd
指令碼的首行加入cd $HADOOP_HOME
,如cd E:\LittleData\hadoop-3.3.0
。
無法訪問localhost:50070
一般是因為hdfs-site.xml
配置遺漏了dfs.http.address
配置項,新增:
<property>
<name>dfs.http.address</name>
<value>0.0.0.0:50070</value>
</property>
然後呼叫stop-all.cmd
,再呼叫start-all.cmd
重啟Hadoop
即可。
Hive連線MySQL異常
注意MySQL
的驅動包是否已經正確拷貝到$HIVE_HOME/lib
下,並且檢查javax.jdo.option.ConnectionURL
等四個屬性是否配置正確。如果都正確,注意是否MySQL
的版本存在問題,或者服務的版本與驅動版本不匹配。
Hive找不到批處理檔案
一般描述是'xxx.cmd' is not recognized as an internal or external command...
,一般是Hive
的命令執行時的異常,需要把Hive 1.x
的原始碼包的bin
目錄下的所有.cmd
指令碼拷貝到$HIVE_HOME/bin
對應的目錄下。
資料夾許可權問題
常見如CreateSymbolicLink
異常,會導致Hive
無法使用INSERT
或者LOAD
命令寫入資料。出現這類問題可以通過下面方式解決:
Win + R
然後執行gpedit.msc
- 計算機設定 -Windows
設定 — 安全設定 - 本地策略 - 使用者許可權分配 - 建立符號連結 - 新增當前使用者。
或者直接使用管理員賬號或者管理員許可權啟動CMD
,然後執行對應的指令碼啟動Hadoop
或者Hive
。
SessionNotRunning異常
啟動HiveServer2
中或者外部客戶端連線HiveServer2
時候有可能出現此異常,具體是java.lang.ClassNotFoundException: org.apache.tez.dag.api.TezConfiguration
的異常。解決方案是:配置檔案hive-site.xml
中的hive.execution.engine
屬性值由tez
修改為mr
,然後重啟HiveServer2
即可。因為沒有整合tez
,重啟後依然會報錯,但是60000
ms後會自動重試啟動(一般重試後會啟動成功):
這算是一個遺留問題,但是不影響客戶端正常連線,只是啟動時間會多了60
秒。
HiveServer2埠衝突
修改配置檔案hive-site.xml
中的hive.server2.thrift.port
屬性值為未被佔用的埠,重啟HiveServer2
即可。
資料節點安全模式異常
一般是出現SafeModeException
異常,提示Safe mode is ON
。通過命令hdfs dfsadmin -safemode leave
解除安全模式即可。
AuthorizationException
常見的是Hive
通過JDBC
客戶端連線HiveServer2
服務時候會出現這個異常,具體是資訊是:User: xxx is not allowed to impersonate anonymous
。這種情況只需要修改Hadoop
的配置檔案core-site.xml
,新增:
<property>
<name>hadoop.proxyuser.xxx.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.xxx.groups</name>
<value>*</value>
</property>
這裡的xxx是指報錯時候具體的系統使用者名稱,例如筆者開發機的系統使用者名稱為doge
然後重啟Hadoop
服務即可。
MapRedTask的許可權問題
常見的是Hive
通過JDBC
客戶端連線HiveServer2
服務執行INSERT
或者LOAD
操作時候丟擲的異常,一般描述是Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask. Permission denied: user=anonymous, access=EXECUTE, inode="/tmp/hadoop-yarn":xxxx:supergroup:drwx------
。通過命令hdfs dfs -chmod -R 777 /tmp
賦予匿名使用者/tmp
目錄的讀寫許可權即可。
小結
沒什麼事最好還是直接在Linux
或者Unix
系統中搭建Hadoop
和Hive
的開發環境比較合理,Windows
系統的檔案路徑和許可權問題會導致很多意想不到的問題。本文參考了大量網際網路資料和Hadoop
和Hive
的入門書籍,這裡就不一一貼出,站在巨人的肩膀上。
(本文完 c-4-d e-a-20201102)