You need to enable JavaScript to run this app.
导航

Go 程序通过 Thrift2 地址访问 HBase 实例

最近更新时间2023.12.22 17:37:17

首次发布时间2023.12.22 14:27:23

表格数据库 HBase 版默认提供了 ZK 连接地址,同时也支持 Thrift 多语言访问,Thrift 是 HBase 标准版实例中的一种服务组件,基于 Apache Thrift(多语言支持的通信框架)开发。本文介绍基于 Go 程序通过 Thrift2 地址访问 HBase 实例的操作步骤。

前提条件

  • 如需通过私网地址访问 HBase 实例,需同时满足如下要求:

    • 已购 ECS 服务器与 HBase 实例在相同私有网络 VPC 下。ECS 服务器的购买方法,请参见购买云服务器

    • 已将 ECS 服务器的 IP 地址添加至 HBase 中的白名单中。白名单设置方法,请参见编辑白名单

  • 如需通过公网地址访问 HBase 实例,需确保运行 Go 程序的设备 IP 地址已加入 HBase 实例的白名单中。白名单设置方法,请参见编辑白名单

  • 已在 ECS 实例或本地设备上安装 Go 程序,建议使用 Go 1.20.x 及以上版本。您可以通过 go version 命令检查当前 Go 的版本。

  • 已在 ECS 实例或本地设备上安装 Thrift 服务,建议使用 0.14.2 或以上版本的 Thrift 服务。关于 Thrift 服务的更多详情,请参见 Apache Thrift

操作步骤

  1. 获取 HBase 实例的 Thrift2 连接地址。
    连接地址查看方法,请参见查看连接地址

    说明

    表格数据库 HBase 版默认未开通 Thrift2 地址,您需要先申请 Thrift2 连接地址,申请方法,请参见申请 Thrift2 连接地址

  2. 在 ECS 实例或本地设备上下载并解压 Go Thrift2 文件,以实现 Go 程序通过 Thrift2 连接 HBase 实例。

    说明

    目前兼容性问题较多,不建议自行编译 HBase Thrift2 文件,建议直接下载使用上述文件即可。

    # 解压下载的文件 
    tar -zxvf hbasegothrift2.tar.gz
    # 进入 hbase 目录
    cd hbase
    
  3. main.go 文件中的 <YourPublicThriftIP> 替换为实际的 Thrift2 连接地址,然后编译运行。

    # 编辑 main.go 文件
    vim main.go
    # 编译 *.go 文件
    go build *.go
    # 运行相关代码
    ./hbase
    
  4. 示例代码如下。

    package main
    
    import (
       "context"
       "fmt"
       "github.com/apache/thrift/lib/go/thrift"
       "net"
       "os"
    )
    
    func main() {
    // 将 <YourPublicThriftIP> 替换为实际的 Thrift2 连接地址
       host := "<YourPublicThriftIP>"
       port := "9090"
    
       protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
       socket, err := thrift.NewTSocket(net.JoinHostPort(host, port)) // 创建连接, 长连接
       if err != nil {
          fmt.Println("failed to create new socket err: " + err.Error())
          os.Exit(1)
       }
       transport := thrift.NewTFramedTransport(socket) // 包装一个TFramedTransport
    
       if err != nil {
          fmt.Fprintln(os.Stderr, "error resolving address:", err)
          os.Exit(1)
       }
       // 该client关联一个连接,NonThreadSafe
       client := NewTHBaseServiceClientFactory(transport, protocolFactory) // hbase客户端与连接关联
       // 执行连接操作
       if err := transport.Open(); err != nil {
          fmt.Fprintln(os.Stderr, "Error opening socket to "+host+":"+port, " ", err)
          os.Exit(1)
       }
       defer transport.Close() // 结束的时候关闭连接
    
       ctx := context.Background()
    
       tableName := "demo_test_table"
       columnFamily := []byte("cf")
       // 数据过期时间,例如设置为7天
       var ttl int32 = 7 * 86400
       columnFamilies := []*TColumnFamilyDescriptor{
          {
             Name:       columnFamily,
             TimeToLive: &ttl,
             // FAST_DIFF
             DataBlockEncoding: TDataBlockEncodingPtr(TDataBlockEncoding_FAST_DIFF),
             // lz4压缩
             CompressionType: TCompressionAlgorithmPtr(TCompressionAlgorithm_LZ4),
          },
       }
       descriptor := &TTableDescriptor{
          TableName: &TTableName{
             Qualifier: []byte(tableName),
          },
          Columns: columnFamilies,
       }
       exists, err := client.TableExists(ctx, descriptor.TableName)
       if err != nil {
          fmt.Println("table exist err :" + err.Error())
          return
       }
       if !exists {
          err = client.CreateTable(ctx, descriptor, nil)
          if err != nil {
             fmt.Println("create table err :" + err.Error())
             return
          }
       }
    
       put := &TPut{
          Row: []byte("foo-row"),
          ColumnValues: []*TColumnValue{
             {
                Family:    columnFamily,
                Qualifier: []byte("sample"),
                Value:     []byte("bar"),
             },
          },
       }
       err = client.Put(ctx, []byte(tableName), put)
       if err != nil {
          fmt.Println("create table err :" + err.Error())
          return
       }
    
       get := &TGet{
          Row: []byte("foo-row"),
       }
       result, err := client.Get(ctx, []byte(tableName), get)
       if err != nil {
          fmt.Println("get err :" + err.Error())
          return
       }
       if result != nil {
          fmt.Println("get ret success")
          fmt.Println("Rowkey:" + string(result.GetRow()))
          for _, cv := range result.ColumnValues {
             fmt.Println("Family:", string(cv.Family), "Qualifer:", string(cv.Qualifier), "Value:", string(cv.Value))
          }
       } else {
          fmt.Println("get ret is nil")
       }
    
    }