1. 程式人生 > >hadoop元件---資料倉庫(五)---通過JDBC連線hive的thrift或者hiveserver2

hadoop元件---資料倉庫(五)---通過JDBC連線hive的thrift或者hiveserver2

我們在上一篇文章中已經學習了Hive的常用命令,但是如果使用其他的語言如何跟Hive進行互動呢。

Thrift簡介

Hive擁有HiveServer(Thrift)或者Hiveserver2元件,提供了JDBC驅動服務,使得我們可以用Java程式碼或者Python來連線Hive並進行一些關係型資料庫的sql語句查詢等操作。

HiveServer或者HiveServer2都是基於Thrift的,但HiveSever有時被稱為Thrift server,而HiveServer2卻不會。既然已經存在HiveServer為什麼還需要HiveServer2呢?這是因為HiveServer不能處理多於一個客戶端的併發請求,這是由於HiveServer使用的Thrift介面所導致的限制,不能通過修改HiveServer的程式碼修正。因此在Hive-0.11.0版本中重寫了HiveServer程式碼得到了HiveServer2,進而解決了該問題。HiveServer2支援多客戶端的併發和認證,為開放API客戶端如JDBC、ODBC提供了更好的支援。

既然HiveServer2提供了更強大的功能,將會對其進行著重學習,但也會簡單瞭解一下HiveServer的使用方法。在命令中輸入

hive --service help

結果如下

我們可以看到上邊輸出項Server List,裡邊顯示出Hive支援的服務列表,beeline cli help hiveserver2 hiveserver hwi jar lineage metastore metatool orcfiledump rcfilecat,下面介紹最有用的一些服務
1、cli:是Command Line Interface 的縮寫,是Hive的命令列介面,用的比較多,是預設服務,直接可以在命令列裡使用

2、hiveserver:這個可以讓Hive以提供Thrift服務的伺服器形式來執行,可以允許許多個不同語言編寫的客戶端進行通訊,使用需要啟動HiveServer服務以和客戶端聯絡,我們可以通過設定HIVE_PORT環境變數來設定伺服器所監聽的埠,在預設情況下,埠號為10000,這個可以通過以下方式來啟動Hiverserver:

bin/hive --service hiveserver -p 10002

其中-p引數也是用來指定監聽埠的

3、hwi:其實就是hive web interface的縮寫它是hive的web藉口,是hive cli的一個web替代方案

4、jar:與hadoop jar等價的Hive介面,這是執行類路徑中同時包含Hadoop 和Hive類的Java應用程式的簡便方式

5、metastore:在預設的情況下,metastore和hive服務執行在同一個程序中,使用這個服務,可以讓metastore作為一個單獨的程序執行,我們可以通過METASTOE——PORT來指定監聽的埠號

從結果可以瞭解到,可以使用

hive <parameters> --service serviceName <serviceparameters>

啟動特定的服務,如cli、hiverserver、hiveserver2等。

在命令列輸入

hive --service hiveserver –help
hive --service hiveserver2 –help

檢視hiveserver的幫助資訊:

從圖中可以看到有些版本hive已經不支援hiveserver了,只能使用hiveserver2。

啟動hiveserver2

使用命令啟動

hive --service hiveserver2

如圖:

hiveserver2配置

配置檔案可以使用如下命令查詢:

whereis hive

如圖:

Hiveserver2允許在配置檔案hive-site.xml中進行配置管理,常用引數有:

hive.server2.thrift.min.worker.threads– 最小工作執行緒數,預設為5。
hive.server2.thrift.max.worker.threads – 最小工作執行緒數,預設為500。
hive.server2.thrift.port– TCP 的監聽埠,預設為10000。
hive.server2.thrift.bind.host– TCP繫結的主機,預設為localhost。

也可以設定環境變數HIVE_SERVER2_THRIFT_BIND_HOST和HIVE_SERVER2_THRIFT_PORT覆蓋hive-site.xml設定的主機和埠號。

hive.server2.thrift.port 10000
hive.server2.thrift.bind.host 192.168.48.130

從Hive-0.13.0開始,HiveServer2支援通過HTTP傳輸訊息,該特性當客戶端和伺服器之間存在代理中介時特別有用。與HTTP傳輸相關的引數如下:

hive.server2.transport.mode – 預設值為binary(TCP),可選值HTTP。
hive.server2.thrift.http.port– HTTP的監聽埠,預設值為10001。
hive.server2.thrift.http.path – 服務的端點名稱,預設為 cliservice。
hive.server2.thrift.http.min.worker.threads– 服務池中的最小工作執行緒,預設為5。
hive.server2.thrift.http.max.worker.threads– 服務池中的最小工作執行緒,預設為500。

預設情況下,HiveServer2以提交查詢的使用者執行查詢(true),如果hive.server2.enable.doAs設定為false,查詢將以執行hiveserver2程序的使用者執行。

<property>
  <name>hive.server2.enable.doAs</name>
  <value>true</value>
</property>

為了防止非加密模式下的記憶體洩露,可以通過設定下面的引數為true禁用檔案系統的快取:

fs.hdfs.impl.disable.cache – 禁用HDFS檔案系統快取,預設值為false。
fs.file.impl.disable.cache – 禁用本地檔案系統快取,預設值為false。

測試hiveserver2

hive自帶了一個thrift的客戶端——-beeline
開啟beeline
使用命令

beeline

連線hiveserver2
使用命令

!connect jdbc:hive2://host253:10000

(host253是hiveserver2所啟動的那臺主機名,埠預設是10000)
如果是在hiveserver2所啟動的那臺主機進行操作也可以使用命令

!connect jdbc:hive2://localhost:10000

有可能需要輸入當前linux使用者名稱和密碼。
正常連線上之後會出現
0: jdbc:hive2://host253:10000>
這時可以嘗試操作資料庫了,使用命令

show databases;

結果如下圖:

HiveServer2 Thrift API

用Java程式碼通過JDBC連線Hiveserver2

新增依賴的包

依賴的jar包有以下幾個:

hadoop-2.2.0/share/hadoop/common/hadoop-common-2.2.0.jar
$HIVE_HOME/lib/hive-exec-0.11.0.jar 
$HIVE_HOME/lib/hive-jdbc-0.11.0.jar 
$HIVE_HOME/lib/hive-metastore-0.11.0.jar  
$HIVE_HOME/lib/hive-service-0.11.0.jar   
$HIVE_HOME/lib/libfb303-0.9.0.jar   
$HIVE_HOME/lib/commons-logging-1.0.4.jar  
$HIVE_HOME/lib/slf4j-api-1.6.1.jar

如果是使用Maven,則加入依賴如下:

<dependency>
        <groupId>org.apache.hive</groupId>
        <artifactId>hive-jdbc</artifactId>
        <version>0.11.0</version>
</dependency>

<dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.2.0</version>
</dependency>

Java程式碼如下

package com.test;

import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.DriverManager;

public class HiveJdbcTest {

    private static String driverName = "org.apache.hive.jdbc.HiveDriver";

    public static void main(String[] args) throws SQLException {
        try {
            Class.forName(driverName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.exit(1);
        }

        Connection con = DriverManager.getConnection("jdbc:hive2://localhost:10000/default", "zzq", "12345");
        Statement stmt = con.createStatement();
        String tableName = "students";
        stmt.execute("drop table if exists " + tableName);
        stmt.execute("create table " + tableName +  " (key int, value string)");
        System.out.println("Create table success!");
        // show tables
        String sql = "show tables '" + tableName + "'";
        System.out.println("Running: " + sql);
        ResultSet res = stmt.executeQuery(sql);
        if (res.next()) {
            System.out.println(res.getString(1));
        }

        // describe table
        sql = "describe " + tableName;
        System.out.println("Running: " + sql);
        res = stmt.executeQuery(sql);
        while (res.next()) {
            System.out.println(res.getString(1) + "\t" + res.getString(2));
        }


        sql = "select * from " + tableName;
        res = stmt.executeQuery(sql);
        while (res.next()) {
            System.out.println(String.valueOf(res.getInt(1)) + "\t" + res.getString(2));
        }

        sql = "select count(1) from " + tableName;
        System.out.println("Running: " + sql);
        res = stmt.executeQuery(sql);
        while (res.next()) {
            System.out.println(res.getString(1));
        }
    }
}

Hiveserver1和hiveserver2的JDBC區別

HiveServer version
HiveServer2
HiveServer1

Connection URL
jdbc:hive2://:
jdbc:hive://:

Driver Class
org.apache.hive.jdbc.HiveDriver
org.apache.hadoop.hive.jdbc.HiveDriver

用Java程式碼通過JDBC連線Hiveserver

我們前面已經熟悉了用Java程式碼通過JDBC連線Hiveserver2,也知道了Hiveserver1和hiveserver2的JDBC區別,連線Hiveserver只需要修改相應的URL和驅動即可。
也就是

private static String driverName = "org.apache.hive.jdbc.HiveDriver";
改為
private static String driverName = "org.apache.hadoop.hive.jdbc.HiveDriver";

Connection con = DriverManager.getConnection("jdbc:hive2://localhost:10002/default", "zzq", "12345");
改為
Connection con = DriverManager.getConnection("jdbc:hive://localhost:10002/default", "zzq", "12345");

Java程式碼如下

package com.test;

import java.sql.SQLException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.DriverManager;

public class HiveJdbcTest {

    private static String driverName = "org.apache.hadoop.hive.jdbc.HiveDriver";

    public static void main(String[] args) throws SQLException {
        try {
            Class.forName(driverName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.exit(1);
        }

Connection con = DriverManager.getConnection("jdbc:hive://localhost:10002/default", "zzq", "12345");
        Statement stmt = con.createStatement();
        String tableName = "students";
        stmt.execute("drop table if exists " + tableName);
        stmt.execute("create table " + tableName +  " (key int, value string)");
        System.out.println("Create table success!");
        // show tables
        String sql = "show tables '" + tableName + "'";
        System.out.println("Running: " + sql);
        ResultSet res = stmt.executeQuery(sql);
        if (res.next()) {
            System.out.println(res.getString(1));
        }

        // describe table
        sql = "describe " + tableName;
        System.out.println("Running: " + sql);
        res = stmt.executeQuery(sql);
        while (res.next()) {
            System.out.println(res.getString(1) + "\t" + res.getString(2));
        }


        sql = "select * from " + tableName;
        res = stmt.executeQuery(sql);
        while (res.next()) {
            System.out.println(String.valueOf(res.getInt(1)) + "\t" + res.getString(2));
        }

        sql = "select count(1) from " + tableName;
        System.out.println("Running: " + sql);
        res = stmt.executeQuery(sql);
        while (res.next()) {
            System.out.println(res.getString(1));
        }
    }
}