天天看點

HBase & thrift & C++程式設計 目錄 1. 前言 2. 啟動和停止thrift2 3. hbase.thrift 4. thrift_helper.h 5. 示例代碼

目錄

目錄 1 1. 前言 1 2. 啟動和停止thrift2 1 2.1. 啟動thrift2 1 2.2. 停止thrift2 1 2.3. 啟動參數 2 3. hbase.thrift 2 3.1. 編譯hbase.thrift 2 4. thrift_helper.h 3 5. 示例代碼 4

1. 前言

本文目的是介紹使用C++如何操作HBase。從HBase 0.94開始,HBase新增thrift2,本文隻介紹和讨論thrift2相關的。hbase-1.1.2使用的thrift估計是thrift-0.9.0版本。

2. 啟動和停止thrift2

2.1. 啟動thrift2

登入HBase master機器,執行以下指令啟動thrift2:hbase-daemon.sh start thrift2。

thrift預設的監聽端口是9090,可以通過參數“-p”指定其它端口。預設使用的Server是TThreadPoolServer。預設使用的Protocol是TBinaryProtocol。

注意用戶端使用的Protocol和Transport和服務端的要保持一緻,否則用戶端在調用時,可能遇到“EAGAIN (timed out)”等錯誤。

2.2. 停止thrift2

hbase-daemon.sh stop thrift2

2.3. 啟動參數

使用“hbase-daemon.sh start thrift2”時,還可以帶以下參數:

參數名 是否預設 參數說明
-h, --help 顯示幫助資訊
-b, --bind 綁定指定位址,但不支援TNonblockingServer和THsHaServer,兩者總是使用“0.0.0.0”
-p, --port 9090 綁室指定端口,預設為9090
-f, --framed 使用TFramedTransport
-c, --compact 使用TCompactProtocol,預設是TBinaryProtocol
-threadpool 使用TThreadPoolServer,為預設Server
-nonblocking 使用實作了FramedTransport的TNonblockingServer
-hsha 使用實作了FramedTransport的THsHaServer

用戶端和hbase thrift2的Transport和Protocol需保持一緻,比如用戶端為FramedTransport,則也需以“-f”啟動hbase thrift2。

否則用戶端在調用時,可能會遇到“EAGAIN (timed out)”等錯誤。

啟動參數資訊來源于官網的頁面:

https://hbase.apache.org/devapidocs/org/apache/hadoop/hbase/thrift2/package-summary.html

以上參數不是給hbase-daemon.sh使用,而是被hbase thrift2使用,可以浏覽相關源代碼了解細節:

hbase-thrift\src\main\java\org\apache\hadoop\hbase\thrift2\ThriftServer.java

hbase-thrift\src\main\java\org\apache\hadoop\hbase\thrift2\ThriftHBaseServiceHandler.java

Ø 啟動示例:

hbase-daemon.sh start thrift2 --framed -nonblocking

3. hbase.thrift

hbaser.thrift檔案在hbase源代碼包(以hbase-1.1.2為例)中的位置:

hbase-thrift\src\main\resources\org\apache\hadoop\hbase\thrift2\hbase.thrift

3.1. 編譯hbase.thrift

保持機器上已安裝好thrift(經測試hbase-1.1.2和thrift-0.9.0相容),然後使用下列指令編譯:thrift --gen cpp -out . hbase.thrift,編譯成功後,會在“-out”指定的目錄下生成以下五個檔案:

THBaseService.h

THBaseService.cpp

hbase_types.h

hbase_types.cpp

hbase_constants.h

hbase_constants.cpp

其中供用戶端使用的是位于檔案THBaseService.h中的類THBaseServiceClient。

4. thrift_helper.h

為了簡化C++用戶端的程式設計,可以使用thrift_helper.h:

https://github.com/eyjian/mooon/blob/master/common_library/include/mooon/net/thrift_helper.h

,它可以幫助簡化對HBase thrift2的調用:

// thrift用戶端輔助類

//

// 使用示例:

// mooon::net::CThriftClientHelper<ExampleServiceClient> client(rpc_server_ip, rpc_server_port);

// try

// {

//     client.connect();

//     client->foo();

// }

// catch (apache::thrift::transport::TTransportException& ex)

//     MYLOG_ERROR("thrift exception: (%d)%s\n", ex.getType(), ex.what());

// catch (apache::thrift::transport::TApplicationException& ex)

//     MYLOG_ERROR("thrift exception: %s\n", ex.what());

// catch (apache::thrift::TException& ex)

// Transport除預設的TFramedTransport (TBufferTransports.h),還可選擇:

// TBufferedTransport (TBufferTransports.h)

// THttpTransport

// TZlibTransport

// TFDTransport (TSimpleFileTransport)

// Protocol除預設的apache::thrift::protocol::TBinaryProtocol,還可選擇:

// TCompactProtocol

// TJSONProtocol

// TDebugProtocol

template <class ThriftClient,

          class Protocol=apache::thrift::protocol::TBinaryProtocol,

          class Transport=apache::thrift::transport::TFramedTransport>

class CThriftClientHelper

5. 示例代碼

// HBase thrift2 C++程式設計示例

#include "THBaseService.h"

#include <inttypes.h> // PRIu64

#include <mooon/net/thrift_helper.h>

#include <mooon/utils/args_parser.h>

#include <vector>

// 請注意用戶端使用的thrift的Transport和Protocol要和hbase thrift2服務端保持一緻,

// 否則調用時,可能總是報逾時,或其它錯誤!!!

// 運作之前,請通過HBase shell建立好表:create 'test','cf1','cf2'

// 或指定版本數:create 'test',{NAME=>'cf1',VERSIONS=>2},{NAME=>'cf2',VERSIONS=>3}

// 删除表,按順序執行以下兩條HBase shell指令:

// disable 'test'

// drop 'test'

STRING_ARG_DEFINE(hbase_ip, "192.168.0.1", "hbase thrift ip");

INTEGER_ARG_DEFINE(uint16_t, hbase_port, 9090, 1000, 50000, "hbase thrift port");

int main(int argc, char* argv[])

{

    std::string errmsg;

    if (!mooon::utils::parse_arguments(argc, argv, &errmsg))

    {

        fprintf(stderr, "parameter error: %s\n", errmsg.c_str());

        exit(1);

    }

    using namespace apache;

    using namespace apache::hadoop;

    std::string hbase_ip = mooon::argument::hbase_ip->value();

    uint16_t hbase_port = mooon::argument::hbase_port->value();

    mooon::net::CThriftClientHelper<hbase::thrift2::THBaseServiceClient> hbase_client(hbase_ip, hbase_port);

    try

        hbase_client.connect(); // 連接配接hbase thrift2 server

        fprintf(stdout, "connect %s:%d ok\n", hbase_ip.c_str(), hbase_port);

        std::string tablename = "test";     // 表名,確定運作之前已建立好

        std::string rowkey = "row1";        // 行Key

        std::string family = "cf1";         // 例族名

        std::string columnname = "f1";      // 例名

        std::string columnvalue = "value1"; // 例值

        // 插入參數設定

        std::vector<hbase::thrift2::TColumnValue> columns_value(1);

        columns_value[0].__set_family(family);

        columns_value[0].__set_qualifier(columnname);

        columns_value[0].__set_value(columnvalue);

        hbase::thrift2::TPut put;

        put.__set_row(rowkey);

        put.__set_columnValues(columns_value);

        hbase_client->put(tablename, put); // 插入,出錯抛異常hbase::thrift2::TIOError

        // 查詢參數設定

        hbase::thrift2::TGet input;

        input.__set_row(rowkey);

        hbase::thrift2::TResult result; // 查詢結果存放在這裡

        hbase_client->get(result, tablename, input); // 查詢,出錯抛異常hbase::thrift2::TIOError

        // 顯示查詢結果

        for (int i=0; i<static_cast<int>(result.columnValues.size()); ++i)

        {

            const hbase::thrift2::TColumnValue& column_value_ref = result.columnValues[i];

            fprintf(stdout, "family[%s]/qualifier[%s]/timestamp[%"PRIu64"]: %s\n", column_value_ref.family.c_str(),

                    column_value_ref.qualifier.c_str(),

                    column_value_ref.timestamp,

                    column_value_ref.value.c_str());

        }

    catch (hbase::thrift2::TIOError& ex)

        fprintf(stderr, "IOError: %s\n", ex.what());

    catch (apache::thrift::transport::TTransportException& ex)

        // 如果和服務端的Transport和Protocol不同,這裡的錯誤是“EAGAIN (timed out)”

        fprintf(stderr, "(%d)%s\n", ex.getType(), ex.what());

    catch (apache::thrift::TApplicationException& ex)

        fprintf(stderr, "%s\n", ex.what());

    catch (thrift::TException& ex)

    return 0;

}

如果thrift用戶端報如下錯誤,有可能是因為一次寫入的資料太多,導緻包過大:

Thrift: Fri Apr 22 17:30:41 2016 TSocket::write_partial() send() <Host: 10.143.136.208 Port: 9090>Connection reset by peer