基於0.14.0版本配置HiveServer2
項目中需要訪問hive作為mondrian的異種數據源執行MDX查詢,而我一般使用hive的時候都是直接通過hive命令行的方式直接執行SQL,或者通過hive的jar包在程序中訪問,在這種方式的使用過程中,訪問的hadoop集群都是公司的集群,之前測試hive的過程中記得自己對hive的jdbc源碼進行了修改,主要是修改了一些hive在實現jdbc中沒有實現但是拋出異常的接口,而mondrian會調用這些接口導致下面的流程走不下去了,整體的修改應該說還是比較簡單的。另外一個問題是當時的hive是沒有使用任何認證機制的,包括hadoop也是沒有認證機制的,現在在公司的hadoop集群上跑需要使用kerberos認證,這一塊自己還不熟悉,還只是知道怎麼用,所以還需要惡補了一下關於kerberos認證的知識。 下面介紹一下我對hive幾種使用方式的理解,首先是hive的元數據庫,它分為三種形式的,第一種是內嵌的derby數據庫,這種方式由於derby會在當前目錄創建一個目錄,所以智能啟動一個hive實例,第二種方式是使用遠程數據庫,也就是使用一個關系數據庫系統,例如mysql等(目前只測試了mysql),hive通過jdbc連接mysql獲取元數據信息,還有一種方式是hive自帶的metaserver,這個server是用來關系元數據的,相當於在真正的元數據管理器之前又搭了一個服務。 在使用的過程中主要有兩種方式使用hive,第一種就是僅僅把hive作為一個可以對文件使用SQL查詢的根據來使用,也就是直接使用hive命令行,亦或者在程序中使用hive提供的函數啟動,在這種情況下我們只需要配置好hive元數據服務器(告訴hive存儲了哪些數據庫和表以及其屬性)和hive的數據倉庫目錄(一般是一個HDFS的目錄),經過測試數據倉庫的目錄只是在創建數據庫的時候有作用,在創建表的時候會在所在數據庫的目錄下創建表的目錄,另外還需要指定hadoop的配置文件和jar包,畢竟hive依賴於hadoop執行任務。 第二種方式就是講hive作為一個提供了SQL接口的數據庫使用,我們可以通過jdbc的方式訪問它,類似於使用mysql的方式,本文主要介紹的就是如何配置這個服務器並且使用hive自帶的客戶端以及使用jdbc的方式連接使用。
接下來就是對hive進行環境配置了,對於hive,我的一般使用方式是使用遠程的mysql做為源數據服務器。而不使用hive自帶的matestore服務器,貌似後者能支持更大的並發,這個暫時沒需求就簡單的來,除了元數據庫還有一個重點就是數據倉庫地址,我配置的我的個人用戶intern的目錄/user/intern,具體配置如下:
hive.metastore.warehouse.dir
/user/intern/
location of default database for the warehouse
javax.jdo.option.ConnectionURL
jdbc:mysql://127.0.0.1:3306/HIVE
JDBC connect string for a JDBC metastore
javax.jdo.option.ConnectionDriverName
com.mysql.jdbc.Driver
Driver class name for a JDBC metastore
javax.jdo.option.ConnectionUserName
root
username to use against metastore database
javax.jdo.option.ConnectionPassword
root
password to use against metastore database
另外,這裡對於hive元數據的創建還需要注意一下,一般情況下我們會選擇使用utf8作為數據庫默認的字符集(應該是為了支持中文),但是如果你使用utf8字符集hive會出現很多莫名其妙的錯誤,讓人摸不到頭腦,所以需要再創建hive數據庫的時候需要指定字符集為latin1,另外還可以讓hive自動幫你創建(我沒有嘗試過,不知道是否可行)。
接下來還需要配置一些關於kerberos認證的東西,具體的配置內容如下:
hive.server2.authentication
KERBEROS
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.
hive.server2.authentication.kerberos.principal
hive/[email protected]
Kerberos server principal
hive.server2.authentication.kerberos.keytab
/home/hzfengyu/hive.keytab
Kerberos keytab file for server principal
這三個配置項分別是配置hiveserver2的認證方式,如果配置不得當客戶端會出現很多問題,默認情況下認證方式是CUSTOM,這裡我們配置成KERBEROS,然後配置kerberos認證需要的keytab文件和principal,一般情況下我們執行kinit也就是需要這兩樣東西,不過不同的是這裡的principal需要指定完成的,而不只是@符號前面的東西(kinit的時候只指定前面的東西就可以了),另外需要注意的是這裡的keytab對應的用戶必須在hadoop上具有可代理執行的權限,這是hiveserver2所需要的,也就是說其實hiveserver2只是一個指定代理的服務器,不同的用戶通過jdbc連接到hiveserver2,根據客戶端不同的keytab用戶代理不同的用戶執行具體的操作。如果該用戶沒有代理的權限,在使用jdbc和hiveserver2建立連接的時候會出現認證錯誤,錯誤的堆棧為:
15/05/01 17:32:33 [main]: ERROR transport.TSaslTransport: SASL negotiation failure
javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7) - UNKNOWN_SERVER)]
at com.sun.security.sasl.gsskerb.GssKrb5Client.evaluateChallenge(GssKrb5Client.java:212)
at org.apache.thrift.transport.TSaslClientTransport.handleSaslStartMessage(TSaslClientTransport.java:94)
at org.apache.thrift.transport.TSaslTransport.open(TSaslTransport.java:253)
at org.apache.thrift.transport.TSaslClientTransport.open(TSaslClientTransport.java:37)
at org.apache.hadoop.hive.thrift.client.TUGIAssumingTransport$1.run(TUGIAssumingTransport.java:52)
at org.apache.hadoop.hive.thrift.client.TUGIAssumingTransport$1.run(TUGIAssumingTransport.java:49)
at java.security.AccessController.doPrivileged(Native Method)
這裡我用的是hive用戶,這個用戶具有代理權限,而我使用jdbc連接的機器使用的用戶是intern,首先在hive機器上執行啟動hiveserver2的命令:
./bin/hive --service hiveserver2
然後再客戶端的機器上通過hive自帶的beeline進行連接:
./bin/beeline
然後使用connect命令連接hiveserver2:
beeline> !connect jdbc:hive2://hiveserver2-ip:10000/foodmart;principal=hive/[email protected];
scan complete in 34ms
Connecting to jdbc:hive2://bitest0.server.163.org:10000/foodmart;principal=hive/[email protected];
Enter username for jdbc:hive2://bitest0.server.163.org:10000/foodmart;principal=hive/[email protected];:
Enter password for jdbc:hive2://bitest0.server.163.org:10000/foodmart;principal=hive/[email protected];:
Connected to: Apache Hive (version 0.14.0)
Driver: Hive JDBC (version 0.14.0)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://bitest0.server.163.org:10000/>
連接的時候需要指定jdbc的url(默認的端口號為10000,也可以在hiveserver2的配置文件中配置),另外還需要制定服務器的principal,也就是在上面配置的那個hive.server2.authentication.kerberos.principal,而客戶端用戶使用的用戶就是客戶端的當前用戶,可以使用klist查看。
除了使用自帶的beeline連接,還可以在程序中使用jdbc進行連接,測試代碼如下:
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.UserGroupInformation;
public class TestHive {
public static void main(String[] args) throws SQLException {
try {
Class.forName("org.apache.hive.jdbc.HiveDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Configuration conf = new Configuration();
conf.setBoolean("hadoop.security.authorization", true);
conf.set("hadoop.security.authentication", "kerberos");
UserGroupInformation.setConfiguration(conf);
try {
UserGroupInformation.loginUserFromKeytab("intern/bigdata", "C:\\Users\\Administrator\\Desktop\\intern.keytab");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Connection conn = DriverManager
.getConnection(
"jdbc:hive2://hiveserver2-ip:10000/foodmart;principal=hive/[email protected];User=;Password=;",
"", "");
Statement stmt = conn.createStatement();
String sql = "select * from account limit 10";
System.out.println("Running: " + sql);
ResultSet res = stmt.executeQuery(sql);
while (res.next()) {
System.out.println(String.valueOf(res.getInt(1)) + "\t"
+ res.getString(2));
}
}
}
好了,這裡說完了如何搭建一個使用kerberos認證的hiveserver2,下一篇在介紹如何使用hive作為mondrian的數據源執行MDX查詢。
最後的最後,介紹一下遇到的一個最大的問題,在配置kerberos認證的時候,我使用的hive版本是0.13.1,按照上面的配置出現了如下的問題:
2015-04-30 17:02:22,602 ERROR [Thread-6]: thrift.ThriftCLIService (ThriftBinaryCLIService.java:run(93)) - Error:
java.lang.NoSuchFieldError: SASL_PROPS
at org.apache.hadoop.hive.thrift.HadoopThriftAuthBridge20S.getHadoopSaslProperties(HadoopThriftAuthBridge20S.java:126)
at org.apache.hive.service.auth.HiveAuthFactory.getSaslProperties(HiveAuthFactory.java:116)
at org.apache.hive.service.auth.HiveAuthFactory.getAuthTransFactory(HiveAuthFactory.java:133)
at org.apache.hive.service.cli.thrift.ThriftBinaryCLIService.run(ThriftBinaryCLIService.java:43)
at java.lang.Thread.run(Thread.java:701)
2015-04-30 17:02:22,605 INFO [Thread[Thread-7,5,main]]: delegation.AbstractDelegationTokenSecretManager (AbstractDelegationTokenSecretManager.java:updateCurrentKey(
222)) - Updating the current master key for generating delegation tokens
2015-04-30 17:02:22,612 INFO [Thread-3]: server.HiveServer2 (HiveStringUtils.java:run(623)) - SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down HiveServer2 at bitest0.server.163.org/10.120.36.85
************************************************************/
最後在google找了一下相關的錯誤,發現了HIVE的這個bug:https://issues.apache.org/jira/browse/HIVE-7620 不知道我遇到的是不是這個問題,但是無論如何就是解決不了這個問題(其實可以說是束手無策),我就換了一下hive的版本,上看說在0.14.0已經解決,我就換成了新的版本,果然這個問題不再出現了,至於到底是否由這個bug引起也不得而知了。