我的 Hive 3.1.2 之旅 【收藏夾吃灰系列】
點擊藍色“有關SQL”關注我喲
加個“星標”,天天與10000人一起快樂成長

圖 | 榖依米
貌似名導們,都有三部曲。
樸贊郁有復仇三部曲,彼得杰克遜有霍比特三部曲。是時候《有關SQL》也該有個大數(shù)據(jù)三部曲了。
繼上部《我的 Hadoop 之旅》,今天又完成這部《我的 Hive 之旅》.
同樣,這部也屬于收藏夾吃灰系列??丛趯懥死泵炊嘧謨?,險些把PP坐出ZC的份兒上,各位看官來個三連唄!
話不多說,上主題:

前奏環(huán)境:
可用的 Hadoop 集群 數(shù)據(jù)庫環(huán)境,如 MySQL Hive 軟件 環(huán)境變量
Hive 軟件
Hive 有 3 個大版本,Hive 1.x.y, Hive 2.x.y, 和Hive 3.x.y. 與本次實驗相對應的是 Hive 3.1.2.
下載地址:https://mirrors.bfsu.edu.cn/apache/hive/hive-3.1.2/

帶 bin 的是安裝文件,而帶 src 的是源碼。
Hive 3.1.2 會支持 Hadoop 3.2.2 嗎,JDK8 夠用嗎,MySQL 5.6 還能不能再戰(zhàn)?等等這些問題,都可以看Hive官方文檔解決!
Hive 官網(wǎng):https://cwiki.apache.org/confluence/display/Hive/GettingStarted#GettingStarted-InstallationandConfiguration
簡單說明:
Java 建議 JDK 7 以上 Hadoop 建議 3 以上 Linux/Windows 首選,Mac 作為開發(fā)
環(huán)境變量
之前安裝了 Hadoop 3.2.2,直接拿來用。不同是,這次要增加一個 /opt/Hive 文件夾
mkdir /opt/Hive
chown -R hadoopadmin /opt/Hive
設置環(huán)境變量:
HIVE_HOME=/opt/Hive/Hive3.1.2
PATH=$PATH:$HIVE_HOME/bin
export HIVE_HOME
export PATH
MySQL 選擇
由于是 Hive 3 版本系列,作為首選元數(shù)據(jù)庫的 MySQL 版本,需重新選擇。合適的版本參考這里:https://cwiki.apache.org/confluence/display/Hive/AdminManual+Metastore+3.0+Administration
最低版本是 MySQL 5.6.17. 其他數(shù)據(jù)庫也可用來作為元數(shù)據(jù)庫存儲
| RDBMS | Minimum Version | javax.jdo.option.ConnectionURL | javax.jdo.option.ConnectionDriverName |
|---|---|---|---|
| MariaDB | 5.5 | jdbc:mysql:// | org.mariadb.jdbc.Driver |
| MS SQL Server | 2008 R2 | jdbc:sqlserver:// | com.microsoft.sqlserver.jdbc.SQLServerDriver |
| MySQL | 5.6.17 | jdbc:mysql:// | com.mysql.jdbc.Driver |
| Oracle | 11g | jdbc:oracle:thin:@// | oracle.jdbc.OracleDriver |
| Postgres | 9.1.13 | jdbc:postgresql:// | org.postgresql.Driver |
MySQL 的安裝,就省去了。有無數(shù)文章提到怎么樣安裝!
比如我的這篇:2019 MySQL8 24小時快速入門(1)
本實驗中,選用 MySQL8. 用戶名:root/MySQLAdmin, 密碼都是:LuckyNumber234.
Hive 配置
Hadoop 安裝配置
Hadoop 的安裝位置十分重要。根據(jù)這個位置,可以拿到 HDFS,YARN 的配置信息,進而得到 namenode 和 resource manager 的訪問地址。
所以,在環(huán)境變量文件中,一定要設置正確 HADOOP_HOME.
另外,在 $HIVE_HOME/bin 下有個文件, hive-config.sh.
--hive.config.sh
# Allow alternate conf dir location.
HIVE_CONF_DIR="${HIVE_CONF_DIR:-$HIVE_HOME/conf}"
export HADOOP_HOME=/opt/Hadoop/hadoop-3.2.2
export HIVE_CONF_DIR=$HIVE_CONF_DIR
export HIVE_AUX_JARS_PATH=$HIVE_AUX_JARS_PATH
在這里也需指定 HADOOP_HOME 的安裝路徑
Hive 配置文件
Hive 的全部數(shù)據(jù),都存儲在 HDFS 上,所以要給 Hive 一個 HDFS 上的目錄:
HDFS DFS -mkdir -p /user/hive/warehouse
HDFS DFS -chmod g+w /user/hive/warehouse在 $HIVE_HOME/conf 下有個文件,hive-default.xml.template. 這是修改 Hive 配置的最重要參數(shù)文件,主要是配置 HDFS 上存放 Hive 數(shù)據(jù)的目錄,以及 Hive MetaStore 的數(shù)據(jù)庫訪問信息
-- hive-site.xml
<property>
<name>system:java.io.tmpdir</name>
<value>/tmp/hive/java</value>
</property>
<property>
<name>system:user.name</name>
<value>${user.name}</value>
</property>
-- 以上兩個屬性,非常重要!底下會講它
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://192.168.31.10/metastore?createDatabaseIfNotExist=true</value>
<description>
JDBC connect string for a JDBC metastore.
To use SSL to encrypt/authenticate the connection, provide database-specific SSL flag in the connection URL.
For example, jdbc:postgresql://myhost/db?ssl=true for postgres database.
</description>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.cj.jdbc.Driver</value>
<description>Driver class name for a JDBC metastore</description>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>MySQLAdmin</value>
<description>Username to use against metastore database</description>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>LuckyNumber234.</value>
<description>password to use against metastore database</description>
</property>
--如果修改了默認hdfs路徑
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
<description>location of default database for the warehouse</description>
</property>
初始化 metastore
各種配置文件完工后,需要初始化 Hive 的元數(shù)據(jù)庫,即 metastore.
schematool -initSchema -dbType mysql[hadoopadmin lib]$ schematool -initSchema -dbType mysqlSLF4J: Class path contains multiple SLF4J bindings.SLF4J: Found binding in [jar:file:/opt/Hive/Hive.3.1.2/lib/log4j-slf4j-impl-2.10.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]SLF4J: Found binding in [jar:file:/opt/Hadoop/hadoop-3.2.2/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]Exception in thread "main" java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;Ljava/lang/Object;)
上面是碰到的第一個坎兒
解決方法** 這是因為 guava.jar 版本沖突引起的。對比 HADOOP_HOME/share/hadoop/common/lib 下的 guava.jar 版本,用最新的版本去覆蓋掉舊版本。
在我的這次實驗中,把 Hive Lib 目錄下的 guava-19.0.jar 刪掉,換上 Hadoop Lib 下的 guava-27.0-jre.jar 就行了。當然,解決不了,請谷歌之!
Follow these steps to fix it:
Go to $HIVE_HOME (%HIVE_HOME%)/lib folder and find out the version of guava. For Hive 3.0.0, it is guava-19.0.jar. Go to $HADOOP_HOME (%HADOOP_HOME%)/share/hadoop/common/lib folder and find out the version of guava. For Hadoop 3.2.1, the version is guava-27.0-jre.jar. If they are not same (which is true for this case), delete the older version and copy the newer version in both. In this case, delete** guava-19.0.jar** in Hive lib folder, and then copy guava-27.0-jre.jar from Hadoop folder to Hive.
第二個問題:com.ctc.wstx.exc.WstxParsingException: Illegal character entity: expansion character
這是 hive-site.xml 中有不可識別字符造成的,定位到這里:
在 "for" 和 "transactional" 之間,有個不可識別字符,刪掉即可。
第三個問題,MySQL 8 的時區(qū)問題
org.apache.hadoop.hive.metastore.HiveMetaException: Failed to get schema version.
Underlying cause: java.sql.SQLException : The server time zone value 'EDT' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specific time zone value if you want to utilize time zone support.
SQL Error code: 0
這里暫停 mysql 服務,配置下 /etc/my.cnf ,加入時區(qū)就行
default_time_zone='+08:00'
Hive 運行
啟動 Hive: hiveserver2
問題:啟動時間太長
^C[hadoopadmin@namenode lib]$ hiveserver2SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".SLF4J: Defaulting to no-operation (NOP) logger implementationSLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.which: no hbase in (/home/hadoopadmin/.local/bin:/home/hadoopadmin/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/opt/java/jdk8/bin:/opt/java/VSCode-linux-x64/bin:/opt/Hadoop/hadoop-3.2.2/bin:/opt/Hadoop/hadoop-3.2.2/sbin:/opt/java/jdk8/bin:/opt/java/VSCode-linux-x64/bin:/opt/Hadoop/hadoop-3.2.2/bin:/opt/Hadoop/hadoop-3.2.2/sbin:/opt/java/jdk8/bin:/opt/java/VSCode-linux-x64/bin:/opt/Hadoop/hadoop-3.2.2/bin:/opt/Hadoop/hadoop-3.2.2/sbin:/opt/Hive/Hive.3.1.2/bin)2021-04-07 11:15:42: Starting HiveServer2Hive Session ID = 8239b67b-ef9f-4596-b802-fc3240e8bf8bHive Session ID = 37aa29dd-e2df-4f4d-9905-deaca088b149Hive Session ID = e821c4f7-7872-4b3b-932b-ac3bd41161ad……?。。〈颂幨∪?span id="go7utgvlrp" class="code-snippet__number">20行Hive Session ID = 6650ff30-bd57-4890-a278-b1cdd75aad45Hive Session ID = fec29941-494c-4a5e-ac88-de45e5e37894Hive Session ID = 71dd04d5-bb0b-4829-b0d3-3d20b5a385ab
這個問題花了點時間。執(zhí)行 hiveserver2 時,并沒有很多可用信息,打印在 console 上。即便使用了原始的啟動 hiveserver2 的 Hive 命令,并將 debug 信息打印出來,也是知道的有限:
hive --service hiveserver2 --hiveconf hive.root.logger=DEBUG,console
我犯了很多技術(shù)者沖動,毛糙的習慣,指望谷歌, stackoverflow 能解決一切的技術(shù)問題。但歷經(jīng)2,3個小時的毒打之后,依然無果。但實際上,想的很難,突破很簡單。就跟平時社交一樣,內(nèi)心戲很足,但臨場時,一點用都排不上。
羅列幾個錯誤信息,要是茫茫網(wǎng)海上,恰好被你碰上,也算咱倆有緣。
就跟所有技術(shù)工具上的紙老虎,戳破表皮,往往簡單而立桿顯影。面對軟件應用出問題時,首要一條原則,那就是看log. Hive 的日志,在 /tmp/{CURRENT_USER}/hive.log 中。
{CURRENT_USER}表示當前賬戶,在我的實驗中,即 hadoopadmin
當我看到很多磚紅色字體時,看到了一線曙光,那意味著有錯誤,有線索。
java.lang.RuntimeException: Error applying authorization policy on hive configuration: java.net.URISyntaxException: Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%7Bsystem:user.name%7D
最關鍵的是這
java.net.URISyntaxException: Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%7Bsystem:user.name%7D
而且重復又重復的,滿屏都是這個錯,我想差不多了,兇手就是它!
再一次感謝 visual studio code, 它幫我省了很多時間。
找到病因,接下來就好解決了:
-- 修改 hive-site.xml
<property>
<name>system:java.io.tmpdir</name>
<value>/tmp/hive/java</value>
</property>
<property>
<name>system:user.name</name>
<value>${user.name}</value>
</property>
應用監(jiān)控頁
通過訪問 namenode:10002,即可登錄監(jiān)控頁,查看應用運行情況:
namenode 是我本次實驗的 master 機器

Hive 實戰(zhàn)
連接客戶端
Hive 2 之后,HiveServer2 成為連接 Hive 的前置代理。
在實驗階段,采用 Beeline 與 dbeaver 連接 HiveServer2,可迅速完成入門級練習。
建立 Hive 鏈接
在運行 HiveServer2 的服務器上,執(zhí)行 beeline
[hadoopadmin hadoopadmin]$ beelineSLF4J: Class path contains multiple SLF4J bindings.SLF4J: Found binding in [jar:file:/opt/Hive/Hive.3.1.2/lib/log4j-slf4j-impl-2.10.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]SLF4J: Found binding in [jar:file:/opt/Hadoop/hadoop-3.2.2/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]Beeline version 3.1.2 by Apache Hivebeeline> !connect jdbc:hive2://localhost:10000Connecting to jdbc:hive2://localhost:10000Enter username for jdbc:hive2://localhost:10000: hadoopadminEnter password for jdbc:hive2://localhost:10000: **********21/04/08 11:28:01 [main]: WARN jdbc.HiveConnection: Failed to connect to localhost:10000Error: Could not open client transport with JDBC Uri: jdbc:hive2://localhost:10000: Failed to open new session: java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hadoopadmin is not allowed to impersonate hadoopadmin (state=08S01,code=0)
在執(zhí)行 connect 時,使用用戶名 hadoopadmin 登錄失敗。
同樣,使用 dbeaver , 一款連接數(shù)據(jù)庫,NoSQL 和大數(shù)據(jù)的跨界神器,

連接過程也不是一帆風順:
Required field 'serverProtocolVersion' is unset! Struct:TOpenSessionResp(status:TStatus(statusCode:ERROR_STATUS, infoMessages:[*org.apache.hive.service.cli.HiveSQLException:Failed to open new session: java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hadoopadmin is not allowed to impersonate anonymous:14:13,……省略*java.lang.RuntimeException:org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hadoopadmin is not allowed to impersonate anonymous:29:7,……省略*org.apache.hadoop.ipc.RemoteException:User: hadoopadmin is not allowed to impersonate anonymous:54:25, org.apache.hadoop.ipc.Client:getRpcResponse:Client.java:1562,……省略org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hadoopadmin is not allowed to impersonate anonymous), serverProtocolVersion:null)
關鍵在這個方法錯誤提示上:(User: hadoopadmin is not allowed to impersonate anonymous:)
hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hadoopadmin is not allowed to impersonate anonymous:14:13,Hive Server 2 會對客戶端進行認證鑒定。授權(quán)認證會有多種方法,所以鏈接的方式會有多樣化。
在這個授權(quán)認證模式上,我卡了很長段時間,死活找不出解決方案。
翻遍了所有的 Log, 對每條報錯信息,看完了谷歌前5頁的推薦內(nèi)容。Hive 官方文檔,更是看了又看。依然,無果,抓狂!
難道,這一次,真要到看源代碼的地步了?搭個環(huán)境,還非得看上個幾千行代碼?
絕對不可能!這樣,Hive 早完蛋了。肯定是我哪里沒想通,或者有什么錯誤消息沒有捕捉到,又或者遺漏了什么參數(shù)配置。
無數(shù)質(zhì)疑的聲音,從我腦子中蹦跶出來……太可怕了!
咖啡因,我需要咖啡因!
提起濾壺,灌入咖啡粉,注入100度的水,煮上一壺咖啡。香氣慢慢傾遍屋子,把我的那些急躁和不安,統(tǒng)統(tǒng)攆走了。
再一次,我深埋在日志中,除了心跳,和噗滋噗滋的沸騰,其他什么都聽不見。
最終,在《Hive Programming Guide》中找到了一丟丟線索。在注腳中,作者給出了這么條說明: HiveServer2 采用了多樣的 Authentication 模式,并受制于 hive.server2.enable.doAs 的配置。
想順利用 beeline 或者 dbeaver 等客戶端登錄 Hive,記住下面這張表:
| hive.server2.authentication | hive.server2.enable.doAs | Driver Authentication Mechanism |
|---|---|---|
NOSASL | FALSE | No Authentication |
KERBEROS | TRUE or FALSE | Kerberos |
KERBEROS | TRUE | Delegation Token |
NONE | TRUE or FALSE | User Name |
PLAINSASL or LDAP | TRUE or FALSE | User Name And Password |
hive.server.2.authentication, 可以配置 5 種認證模式:
NONE NOSASL KERBEROS PLANSASL LDAP
值得注意的是:
NONE 是需要認證的,和字面意思不一樣。 NOSASL 禁止使用簡單安全認證 - Simple Authentication and Security Layer (SASL)
hive.server2.enable.doAs 可選值有 2個:
FALSE TRUE
doAs 參數(shù),指定了遠程訪問 hiveserver2 的程序,賬戶是否獨有。hiveserver2 的啟動賬戶,天生對 hive 有訪問權(quán)限。
當 doAs = FALSE 時,遠程調(diào)用就以啟動 hiveserver2 的賬戶,訪問 hive, 所擁有的權(quán)限就繼承自 hiveserver2 啟動賬戶。
當 doAs = TRUE 時,遠程調(diào)用就以獨立的賬戶,訪問 hive, 所擁有的權(quán)限單獨配置。
本次實驗,選擇了 NONE + FALSE 的組合,采用 No Authentication 的策略。
--hive-site.xml
<property>
<name>hive.server2.authentication</name>
<value>NOSASL</value>
<description>
Expects one of [nosasl, none, ldap, kerberos, pam, custom].
Client authentication types.
NONE: no authentication check
LDAP: LDAP/AD based authentication
KERBEROS: Kerberos/GSSAPI authentication
CUSTOM: Custom authentication provider
(Use with property hive.server2.custom.authentication.class)
PAM: Pluggable authentication module
NOSASL: Raw transport
</description>
</property>
<property>
<name>hive.server2.enable.doAs</name>
<value>false</value>
<description>
Setting this property to true will have HiveServer2 execute
Hive operations as the user making the calls to it.
</description>
</property>
再執(zhí)行 beeline:
beeline> !connect jdbc:hive2://192.168.31.10:10000/default;auth=noSasl
Connecting to jdbc:hive2://192.168.31.10:10000/default;auth=noSasl
Enter username for jdbc:hive2://192.168.31.10:10000/default: root
Enter password for jdbc:hive2://192.168.31.10:10000/default:
Connected to: Apache Hive (version 3.1.2)
Driver: Hive JDBC (version 3.1.2)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://192.168.31.10:10000/default> show databases ;
DEBUG : Acquired the compile lock.
INFO : Compiling command(queryId=hadoopadmin_20210409105440_2c63fa0a-6c15-41cb-b11c-64284ff6a1ea): show databases
INFO : Concurrency mode is disabled, not creating a lock manager
INFO : Semantic Analysis Completed (retrial = false)
INFO : Returning Hive schema: Schema(fieldSchemas:[FieldSchema(name:database_name, type:string, comment:from deserializer)], properties:null)
INFO : Completed compiling command(queryId=hadoopadmin_20210409105440_2c63fa0a-6c15-41cb-b11c-64284ff6a1ea); Time taken: 0.977 seconds
INFO : Concurrency mode is disabled, not creating a lock manager
INFO : Executing command(queryId=hadoopadmin_20210409105440_2c63fa0a-6c15-41cb-b11c-64284ff6a1ea): show databases
INFO : Starting task [Stage-0:DDL] in serial mode
INFO : Completed executing command(queryId=hadoopadmin_20210409105440_2c63fa0a-6c15-41cb-b11c-64284ff6a1ea); Time taken: 0.057 seconds
INFO : OK
INFO : Concurrency mode is disabled, not creating a lock manager
DEBUG : Shutting down query show databases
+----------------+
| database_name |
+----------------+
| default |
+----------------+
最重要的是這段鏈接:
beeline> !connect jdbc:hive2://192.168.31.10:10000/default;auth=noSasl
Connecting to jdbc:hive2://192.168.31.10:10000/default;auth=noSasl
Enter username for jdbc:hive2://192.168.31.10:10000/default: root
Enter password for jdbc:hive2://192.168.31.10:10000/default:
因采用了 No Authentication 的策略,在構(gòu)建 Jdbc 連接字符串時,需加 auth=noSasl 設定。
默認的數(shù)據(jù)庫 default; 默認用戶名 root, 密碼為空。

如果第一次打開 Hive 鏈接,dbeaver 自動提示要下載驅(qū)動
默認驅(qū)動配置,認證,用戶名,密碼,默認數(shù)據(jù)庫,需要點擊 [Edit Driver Settings] 做修改:


除此之外, HiveServer2 采用了 thrift 協(xié)議,它有默認的用戶名和密碼,可從hive-site.xml中找到:
<property>
<name>hive.server2.thrift.client.user</name>
<value>anonymous</value>
<description>Username to use against thrift client</description>
</property>
<property>
<name>hive.server2.thrift.client.password</name>
<value>anonymous</value>
<description>Password to use against thrift client</description>
</property>
用 anonymous 也可以訪問 hive.
測試建表
表一張表試下:
create table dimuser (userid int, username string)
建表的 HQL(Hive Query Language) 和 RDBMS SQL 語法相似,但背后隱藏著巨大的細節(jié):
CREATE TABLE `default.dimuser`(
`userid` int,
`username` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
'hdfs://namenode:9000/user/hive/warehouse/dimuser'
TBLPROPERTIES (
'bucketing_version'='2',
'transient_lastDdlTime'='1617981077');
這是 Hive 翻譯的 DDL(Data Definition Language) ,還是相當復雜的。
再來看表,已經(jīng)掛上來了:

希望本次實戰(zhàn)記錄,能幫到你!
往期精彩:
