关于sql server 读取byte[]类型数组问题_关于thrift协议改进畅想

Thrift简介

thrift协议你主要提供3种编解码格式协议,Binary、Compact、SimpleJson(还有debug、virtual);其中最常用的是Binary协议,其传输层一般以BufferedTransport、BufferedTransport居多;这里讨论主要以Binary协议为基础。本身来说,Binary协议不做任何压缩,只是为了支持跨系统网络传输(当然也可以做本地编解码工具)。

protobuf、flat对比

Compact协议对标protobuf编码,主要是利用varint压缩;Binary对标的是flat编码

和protobuf对比,他们thrift区别在于:

  • protobuf、flat协议编解码方式只有一种,而thrift有3种
  • protobuf以小端序传输,thrift以大端序传输,它们都只是跨系统网络传输;flat仅适用于机型系统(大小端相同)
  • protobuf支持反射、thrift不支持
  • protobuf3.0后支持更丰富的类型比如time、date、duration,thrift不支持

Binary编码介绍

Binary整体编码形式如下:

简单类型(byte、int8、int16、int32、int64、float64): 数据类型(1字节)+ 数据

字符串(string):数据类型(1字节)+ 数据长度(4字节)+数据

数组([]byte、[]int32、[]int64等):数据类型(1字节)+数组长度(4字节)+ 连续数据...

数组结构([]struct):数据类型(1字节)+数组长度(4字节)+ 连续(struct数据)...

字符串数组([]string):数据类型(1字节)+数组长度(4字节)+连续 (字符串长度+数据)...

map:数据类型(1字节)+key类型+value类型+map长度(4字节)+连续(key+value)...

对于非字符串、[]byte类型的超过2个连续字节的编码(包含长度),都是大端序

奇思妙想

如上面所说,Binary编码不做任何数据压缩,且是大端编码,这种方式是否足够好呢?对于编解码工具来说,除了能做跨网络传输编解码协议,好像看不到任何其他收益;

想想的确是这样

  • 相比protobuf,不能做压缩
  • 相比flat,性能上有损

既然,thrift的compact本身是对标protobuf,binary是对标flat,那我们可以可以把Binary编解码性能提升到等同flat呢???

答案是可以!!!

但是有一个问题待解决,flat是无法跨系统网络传输的,因为编码本身是依赖机器自身大小端。可以绕过去吗?

可以假如我们在编码的时候,把机器大小端信息带上去不就可以了!!!标识放到哪?放到Version头部即可!

具体实现

在编码的时候,新定义一种ProtocolID类型,叫ProtocolIDFlatLtlEnd(Flate小端序编码),因为ProtocolIDBinary本身是大端序(可以看做是flat变种),需要再新增ProtocolIDFlatBigEnd。

以go为例

const (

ProtocolIDBinary ProtocolID = 0

ProtocolIDJSON ProtocolID = 1

ProtocolIDCompact ProtocolID = 2

ProtocolIDDebug ProtocolID = 3

ProtocolIDVirtual ProtocolID = 4

ProtocolIDSimpleJSON ProtocolID = 5

ProtocolIDFlatLtlEnd ProtocolID = 6

)

Binary统一flat编码

  • 编码:
    • 先判断本机大小端:如果是大端,则头部写ProtocolID= ProtocolIDBinary,否则头部写ProtocolID= ProtocolIDFlatLtlEnd
    • 把数据字段拷贝到内存即可,无需先做大端转换,再拷贝;特别的,对于数组类型[]int16,[]int32,[]int64,直接大段数据拷贝,无需遍历做端转换后一个个拷贝
  • 解码:
    • 获取协议头部ProtocolID,如果ProtocolID=ProtocolIDBinary且本机是大端;或者如果ProtocolID= ProtocolIDFlatLtlEnd且本机是小端,直接从内存copy数据到字段即可,无需做大端转换;特别的,对于数组类型[]int16,[]int32,[]int64,直接大段数据拷贝到数组,无需多次分段大端转换再赋值

如何判断大小端,参考如下代码:

var isLittleEndian bool = true

func init() {

a := uint16(0x1234)

ptr := (*byte)(unsafe.Pointer(&a))

if *ptr == 0x12 {

isLittleEndian = false

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值