golang-thrift 使用hbase教程

1.hbase知识

	进入shell命令: /usr/local/hbase/bin/hbase shell 
	create 'ulive_test', 'i'  // 创建一个列族 i
	help // 查看所有命令
	list // 查看所有表
	describe 'student' // 查看表结构
	// 删除表之前需要 disable 
	disable 'student'
	drop 'student'
	命名空间
	list_namespace 
	创建空间
	create_namespace 'gitxuzan'
	create "gitxuzan:statue" ,'info'
	disable "gitxuzan:statue"
	drop "gitxuzan:stu"
	drop_namespace 'gitxuzan'
	put 'sut' ,'1001', 'info1:name', 'zhangsan'  //新增数据1001是rowkey
	get 'stu','1001' // 查询

更多命令相关使用查阅
在这里插入图片描述

2.Go使用Thrift连接HBase(🆚resetful api接口效率要高,相关开源包:https://github.com/tsuna/gohbase)

mac 通过 brew安装,windows 系统下载 thrift.exe 可执行文件 (windows下载链接:http://archive.apache.org/dist/thrift/)

 brew install thrift
 查看版本 thrift -version (注意版本号最好是能在github.com/apache/thrift 找到对应tag)
	Thrift version 0.14.1

3.下载HBase源码

https://hbase.apache.org/downloads.html
在这里插入图片描述
在这里插入图片描述

解压后来到 hbase-thrift\src\main\resources\org\apache\hadoop\hbase\thrift\Hbase.thrift 
执行: thrift -gen go -o . ./Hbase.thrift
生成 gen-go 放到你的项目,注意里面可能有string 类型的语法错误,需要自己替换

4.go 源码部署

注意:thrift 插件和你使用的版本 https://github.com/apache/thrift 需要一致,我这边的代码是使用的thrift v0.14.1版本

一个链接和插入的例子(表要先创建)
package hbases

import (
	"context"
	"github.com/Xuzan9396/zlog"
	"github.com/apache/thrift/lib/go/thrift"
	"github.com/panjf2000/ants/v2"
	"github.com/spf13/viper"
	"myhbase/common"
	"myhbase/global"
	"myhbase/gen-go/hbase"
	"net"
	"strconv"
	"sync"
	"time"
)

type NewHbase struct {
	data  chan []*common.UserEventInfo
	onces sync.Once
}

var HBASE *NewHbase

func GetModel() *NewHbase {
	if HBASE == nil {
		// 启动hbase
		model := &NewHbase{
			data: make(chan []*common.UserEventInfo, 2000),
		}
		HBASE = model
		model.cient()
		go model.HbasePull()
		go model.ping_cient()
	}

	return HBASE
}

func (c *NewHbase) cient() {
	host, portStr, table := viper.GetString("hbase.host"), viper.GetString("hbase.port"), viper.GetString("hbase.table")

	var err error
	// -------------------------    -----------------------
	protocolFactory := thrift.NewTBinaryProtocolFactoryConf(&thrift.TConfiguration{
		        TBinaryStrictRead:  thrift.BoolPtr(true),
		        TBinaryStrictWrite: thrift.BoolPtr(true),
		     })
	zlog.F().Info(host," ",portStr)
	global.Transport, err = thrift.NewTSocketConf(net.JoinHostPort(host, portStr),&thrift.TConfiguration{

		ConnectTimeout: time.Second*60,
		 SocketTimeout:  time.Second*60,
		     })
	if err != nil {
		zlog.F().Error(err)
		return
	}


	client := hbase.NewHbaseClientFactory(global.Transport, protocolFactory)
	if err := global.Transport.Open(); err != nil {
		zlog.F().Error(err)
		return
	}
	global.Hbase = client


	argvalue0 := []byte(table)
	value0 := hbase.Bytes(argvalue0)
	bools, err := client.IsTableEnabled(context.TODO(),value0)
	if err != nil {
		zlog.F().Error(err)
	}
	if bools == true {
		zlog.F().Info("表已存在:" + table)
	}

}

func (c *NewHbase) ping_cient() {
	defer func() {
		if r := recover(); r != nil {
			zlog.F().Error(r)
		}
	}()
	times := time.NewTicker(5 * time.Second)
	var err error
	for {
		select {
		case <-times.C:

			if global.Transport != nil && global.Transport.IsOpen() {
				zlog.F().Info("已经isopen")
				continue
			}

			zlog.F().Info("hbase断开链接,准备正在重连!")
			//global.LOG.Info("test!")
			host, portStr := viper.GetString("hbase.host"), viper.GetString("hbase.port")
			// -------------------------    -----------------------
			protocolFactory := thrift.NewTBinaryProtocolFactoryConf(&thrift.TConfiguration{
				TBinaryStrictRead:  thrift.BoolPtr(true),
				TBinaryStrictWrite: thrift.BoolPtr(true),
			})
			zlog.F().Info(host," ",portStr)
			global.Transport, err = thrift.NewTSocketConf(net.JoinHostPort(host, portStr),&thrift.TConfiguration{
				ConnectTimeout: time.Second*60,
				SocketTimeout:  time.Second*60,
			})
			if err != nil {
				zlog.F().Error(err)
				return
			}

			client := hbase.NewHbaseClientFactory(global.Transport, protocolFactory)
			if err := global.Transport.Open(); err != nil {
				zlog.F().Error(err)

				return
			}
			global.Hbase = client
			zlog.F().Info("重新连接池状态正常")
		}
	}

}

func (c *NewHbase) HbasePull() {
	defer func() {
		if r := recover(); r != nil {
			//global.LOG.Error("err", zap.Any("错误pull", r))
			zlog.F().Error(r)
		}
	}()
	p, _ := ants.NewPoolWithFunc(1, func(i interface{}) {
		data, ok := i.([]*common.UserEventInfo)
		if !ok {
			return
		}

		c.Put(data)

	})
	defer p.Release()
	for {
		select {
		case r := <-c.data:

			_ = p.Invoke(r)

		}
	}

}

func (c *NewHbase) Set(data []*common.UserEventInfo) {
	select {
	case c.data <- data:
	default:
		//global.LOG.Info("丢弃了")
		zlog.F().Info("丢弃了")

	}
}

func (c *NewHbase) Put(data []*common.UserEventInfo) {
	tableName, col := viper.GetString("hbase.table"), "i"
	//col := "i"
	sendMuData := make([]*hbase.BatchMutation, 0)
	for _, value := range data {
		if value.UserId <= 0 {
			continue
		}

		userIdStr := strconv.FormatInt(value.UserId, 10)
		timeStr := strconv.FormatInt(value.Time, 10)
		if len(timeStr) == 13 {
			timeStr = timeStr[:10]
		}
		widthStr := strconv.Itoa(value.Properties.ScreenWidth)
		heightStr := strconv.Itoa(value.Properties.ScreenHeight)

		rowKey := userIdStr + timeStr
		//m := hbase.Mutation{false, []byte(col + ":name"), []byte("xuzan2"), true}
		sendArr := []*hbase.Mutation{
			{false, []byte(col + ":user_id"), []byte(userIdStr), true},
			{false, []byte(col + ":event"), []byte(value.Event), true},
			{false, []byte(col + ":device_id"), []byte(value.DeviceID), true},
			{false, []byte(col + ":time"), []byte(timeStr), true},
			{false, []byte(col + ":lib"), []byte(value.Properties.Lib), true},
			{false, []byte(col + ":lib_version"), []byte(value.Properties.LibVersion), true},
			{false, []byte(col + ":model"), []byte(value.Properties.Model), true},
			{false, []byte(col + ":os"), []byte(value.Properties.Os), true},
			{false, []byte(col + ":screen_width"), []byte(widthStr), true},
			{false, []byte(col + ":screen_height"), []byte(heightStr), true},
			{false, []byte(col + ":manufacturer"), []byte(value.Properties.Manufacturer), true},
			{false, []byte(col + ":app_version"), []byte(value.Properties.AppVersion), true},
			{false, []byte(col + ":element_id"), []byte(value.Properties.ElementID), true},
			{false, []byte(col + ":activity"), []byte(value.Properties.Activity), true},
		}

		sendMuData = append(sendMuData, &hbase.BatchMutation{
			[]byte(rowKey), sendArr,
		})

	}

	if len(sendMuData) > 0 {

		err :=  global.Hbase.MutateRows(
			context.TODO(),
			[]byte(tableName),
			sendMuData,
			nil)
		if err == nil {
			zlog.F().Info("批量插入成功")
		} else {
			zlog.F().Error(err)
		}
	}
}

5.遇到的bug

bug1: "err": "mutateRows failed: out of sequence response
看这个问题,处理方式是减少了并发请求了,之前是开了5个线程,一个连接去请求的,改成一个线程就好了,如果需要并发,可能需要多个连接 (相关原因:https://bbs.huaweicloud.com/blogs/197750)
bug2: : write: broken pip  ,服务端修改了connect时间,服务器改了hbase配置hbase.thrift.server.socket.read.timeout (https://blog.csdn.net/u011342882/article/details/86300625)

6.其他相关链接

https://www.daryl.top/2021/04/go%E4%BD%BF%E7%94%A8thrift%E8%BF%9E%E6%8E%A5hbase/

https://blog.csdn.net/lesorb/article/details/64442673

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
golang-lru 是一个 Golang 语言实现的 LRU 缓存库,它提供了一个简单易用的 API 用于创建和使用 LRU 缓存。 下面是一个简单的使用示例: ```go package main import ( "fmt" "github.com/hashicorp/golang-lru" ) func main() { // 创建一个 LRU 缓存,容量为 2 cache, _ := lru.New(2) // 添加两个元素到缓存中 cache.Add("key1", "value1") cache.Add("key2", "value2") // 从缓存中获取一个元素 if v, ok := cache.Get("key1"); ok { fmt.Println(v.(string)) } // 添加一个新元素到缓存中,此时缓存容量已满,会自动淘汰最久未使用的元素 "key2" cache.Add("key3", "value3") // 遍历缓存中的所有元素 for _, k := range cache.Keys() { if v, ok := cache.Get(k); ok { fmt.Println(k, v.(string)) } } } ``` 运行上述代码,将会输出: ``` value1 key1 value1 key3 value3 ``` 在这个示例中,我们首先使用 `lru.New()` 函数创建了一个容量为 2 的 LRU 缓存。然后我们添加了两个元素到缓存中,并从缓存中获取了一个元素。接着我们添加了一个新元素,此时缓存已满,会自动淘汰最久未使用的元素 "key2"。最后我们遍历了缓存中的所有元素,输出了它们的键和值。 除了 `Add()` 和 `Get()` 方法外,golang-lru 还提供了 `Remove()` 和 `Contains()` 方法来删除和判断缓存中是否存在某个元素,以及 `Len()` 和 `Clear()` 方法来获取缓存中元素的数量和清空缓存。 golang-lru 还支持并发安全,你可以通过 `NewWithOptions()` 函数创建一个并发安全的 LRU 缓存,具体用法请参考官方文档:https://pkg.go.dev/github.com/hashicorp/golang-lru。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gitxuzan_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值