表格数据库 HBase 版默认提供了 ZK 连接地址,同时也支持 Thrift 多语言访问,Thrift 是 HBase 标准版实例中的一种服务组件,基于 Apache Thrift(多语言支持的通信框架)开发。本文介绍基于 Go 程序通过 Thrift2 地址访问 HBase 实例的操作步骤。
如需通过私网地址访问 HBase 实例,需同时满足如下要求:
如需通过公网地址访问 HBase 实例,需确保运行 Go 程序的设备 IP 地址已加入 HBase 实例的白名单中。白名单设置方法,请参见编辑白名单。
已在 ECS 实例或本地设备上安装 Go 程序,建议使用 Go 1.20.x 及以上版本。您可以通过 go version
命令检查当前 Go 的版本。
已在 ECS 实例或本地设备上安装 Thrift 服务,建议使用 0.14.2 或以上版本的 Thrift 服务。关于 Thrift 服务的更多详情,请参见 Apache Thrift。
获取 HBase 实例的 Thrift2 连接地址。
连接地址查看方法,请参见查看连接地址。
说明
表格数据库 HBase 版默认未开通 Thrift2 地址,您需要先申请 Thrift2 连接地址,申请方法,请参见申请 Thrift2 连接地址。
在 ECS 实例或本地设备上下载并解压 Go Thrift2 文件,以实现 Go 程序通过 Thrift2 连接 HBase 实例。
说明
目前兼容性问题较多,不建议自行编译 HBase Thrift2 文件,建议直接下载使用上述文件即可。
# 解压下载的文件 tar -zxvf hbasegothrift2.tar.gz # 进入 hbase 目录 cd hbase
将 main.go
文件中的 <YourPublicThriftIP>
替换为实际的 Thrift2 连接地址,然后编译运行。
# 编辑 main.go 文件 vim main.go # 编译 *.go 文件 go build *.go # 运行相关代码 ./hbase
示例代码如下。
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 // 该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") } }