Flatbuffer的简单使用

Flatbuffer

安装使用

参考链接:blog.51cto.com/onebig/2122019

一、FlatBuffers简介

FlatBuffers为Google发布的一个跨平台,提供多种语言接口,注重性能和资源使用的序列化类库。目前该类库提供C++, C#, C, Go, Java, JavaScript, PHP, and Python语言接口。该序列化类库多用于移动端手游数据传输以及特定的对性能有较高要求的应用。 接下来我们将学习FlatBuffers环境搭建并且使用Java语言完成一次简单的序列化例子。

  • 编译flatc工具

  • 编写一个FlatBuffers的scheme文件,.fbs文件

  • 使用flatc工具编译scheme文件,生成对应语言的数据对象头文件/类

  • 使用FlatBufferBuilder序列化对象

  • 反序列化数据对象

编译flatc工具

下载flatc源码

git clone git@github.com:google/flatbuffers.git
cd flatbuffers/
sudo cmake -G "Unix Makefiles" //生成makefile文件
sudo make 
sudo make install
flatc --version  //显示版本

编写FlatBuffers的scheme文件

基本类型:

  • 8 bit: byte ubyte bool

  • 16 bit: short ushort

  • 32 bit: int uint float

  • 64 bit: long ulong double

复杂类型:

  • 数组 (用中括号表示 [type]). 不支持嵌套数组,可以用table实现

  • 字符串 string, 支持 UTF-8 或者 7-bit ASCII. 对于其他编码可以用数组 [byte]或者[ubyte]表示。

  • Struct 只支持基本类型或者嵌套Struct

  • Table 类似Struct,但是可以支持任何类型

先编写test.fbs

namespace Block;
​
table Block {
 id: long;
 hash: string;
 flag: bool;
 txs: [Tx];
}
table Tx {
 hash: string;
 value: double;
}
​
root_type Block;

参考链接:github.com/halfrost/Halfrost-Field...

Go使用FlatBuffers

编译scheme文件为go文件,会生成Block.go, Tx.go文件

flatc -g myschema.fbs

安装go扩展包

go get -v github.com/google/flatbuffers/go
序列化数据

把对象转为二进制数据

package main
import (
  "fmt"
  fbs "letcode/flatbuff/fbs/block"
  flatbuffers "github.com/google/flatbuffers/go"
)
type Block struct {
  Id   int64
  Hash string
  Flag bool
  Txs  []Tx
}
type Tx struct {
  Hash  string
  Value float64
}
func main() {
  txone := Tx{Hash: "adfadf", Value: 123}
  txtwo := Tx{Hash: "adfadf", Value: 456}
  block := Block{Id: 1,Hash: "aadd",Flag: true,}
  //初始化buffer,大小为0,会自动扩容
  builder := flatbuffers.NewBuilder(0)
  //第一个交易
  txoneh := builder.CreateString(txone.Hash)//先处理非标量string,得到偏移量
  fbs.TxStart(builder)
  fbs.TxAddHash(builder, txoneh)
  fbs.TxAddValue(builder, txone.Value)
  ntxone := fbs.TxEnd(builder)
  //第二个交易
  txtwoh := builder.CreateString(txtwo.Hash)
  fbs.TxStart(builder)
  fbs.TxAddHash(builder, txtwoh)
  fbs.TxAddValue(builder, txtwo.Value)
  ntxtwo := fbs.TxEnd(builder)
  //block
  //先处理数组,string等非标量
  fbs.BlockStartTxsVector(builder, 2)
  builder.PrependUOffsetT(ntxtwo)
  builder.PrependUOffsetT(ntxone)
  txs := builder.EndVector(2)
  bh := builder.CreateString(block.Hash)
  //再处理标量
  fbs.BlockStart(builder)
  fbs.BlockAddId(builder, block.Id)
  fbs.BlockAddHash(builder, bh)
  fbs.BlockAddFlag(builder, block.Flag)
  fbs.BlockAddTxs(builder, txs)
  nb := fbs.BlockEnd(builder)
  builder.Finish(nb)
  buf := builder.FinishedBytes() //返回[]byte
  fmt.Println(buf)
}

要序列化block,首先处理非标量的序列化,得到偏移量。

反序列化

读取二进制数据转为对象

func DecodeToBlock(filename string) Block {
    var (
        block Block
    )
    buf, err := ioutil.ReadFile(filename)
    if err != nil {
        panic(err)
    }
    //传入二进制数据
    b := fbs.GetRootAsBlock(buf, 0)
    block.Flag = b.Flag()
    block.Hash = string(b.Hash())
    block.Id = b.Id()
    len := b.TxsLength()
    for i := 0; i < len; i++ {
        tx := new(fbs.Tx)
        ntx := new(Tx)
        if b.Txs(tx, i) {
            ntx.Hash = string(tx.Hash())
            ntx.Value = tx.Value()
        }
        block.Txs = append(block.Txs, *ntx)
    }
    return block
}
  1. 编码性能:flatbuf 的编码性能要比 protobuf 低。在JSON、protobuf 和 flatbuf 之中,flatbuf 编码性能最差,JSON 介于二者之间。

  2. 编码后的数据长度:由于通常情况下,传输的数据都会做压缩。在不压缩的情况下,flatbuffer 的数据长度是最长的,理由也很简单,因为二进制流内部填充了很多字节对齐的 0,并且原始数据也没有采取特殊的压缩处理,整个数据膨胀的更大了。不管压不压缩,flatbuffer 的数据长度都是最长的。JSON 经过压缩以后,数据长度会近似于 protocol buffer。protocol buffer 由于自身编码就有压缩,再经过 GZIP 这些压缩算法压缩以后,长度始终维持最小。

  3. 解码性能:flatbuffer 是一种无需解码的二进制格式,因而解码性能要高许多,大概要比 protobuf 快几百倍的样子,因而比 JSON 快的就更多了。

结论是,如果需要重度依赖反序列化的场景,可以考虑用 flatbuffer。protobuf 则是表现出各方面都很均衡的能力。

本作品采用《CC 协议》,转载必须注明作者和本文链接
用过哪些工具?为啥用这个工具(速度快,支持高并发...)?底层如何实现的?
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!