Protobuf入门

在Kafka中,发送的消息是字节数组,所以就须要一个方法来将消息对象序列化为字节数组,在消费者端再反序列化为对象。最经常使用的序列化格式就是JSON了。虽然JSON对人类很是友好,可是对于机器来讲,更容易进行序列化和反序列化的格式仍是二进制的格式。git

Protobuf(Protocol buffers)是由Google开发的一种二进制协议,用于对结构化数据进行序列化和反序列化。这种格式占用空间更少,更加简单易于维护,同时拥有更好的性能。对于机器之间的通讯,Protobuf是比XML和JSON等格式更好的一种选择。github

Protobuf的使用相比之下更加复杂,须要编写.proto格式的文件来定义数据格式,以后经过protoc编译器将其编译到对应的语言,以后再在程序中引用。golang

使用

安装

首先就是安装protoc编译器,这个编译器能够直接到github上下载二进制包,解压到对应位置并设置PATH便可。shell

以后就是安装对应语言的客户端,对于golang,执行下面两条语句安装就能够了:数组

go get github.com/golang/protobuf/proto
go get github.com/golang/protobuf/protoc-gen-go

编译

以后新建一个.proto文件,在其中定义消息的格式:性能

syntax = "proto3";
package test;

option go_package = "proto/test";

message Award {
    int64 uid = 1;
    int64 awardId = 2;
    string userName = 3;
}

而后使用protoc编译器将其编译到go文件就好了:ui

protoc --go_out=. proto/*.proto

在go程序中引入生成的包就能够进行序列化和反序列化了:google

import pb "proto/test"

func marshal() {
    award := &pb.Award{
		Uid:      628,
		AwardId:  1,
		UserName: "Haruka",
	}
	msg, err := proto.Marshal(award)
}

func unmarshal() {
    award := &pb.Award{}
	if err := proto.Unmarshal(msg.Value, award); err != nil {
		panic(err)
	}
}

proto3语言

.proto文件的第一行就是syntax = "proto3";,用于声明该文件是proto3版本的。以后能够声明package用于避免命名冲突,最后就能够定义message了。url

字段ID

message的每一个字段都要分配一个惟一的ID,最小是1最大是2^29 - 1,同时不能使用 1900019999的ID。ID能够任意分配,可是115只会占用1个字节,而16~2047会占用2个字节,所以应尽可能从小开始分配,并将小的分配给最常常出现的字段。code

可使用reserved来对字段名和ID进行保留,通常用于为将来新增字段保留,或者保留删除字段来避免以后的字段使用,防止发生冲突:

message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}

字段类型

字段的类型默认是singular,也就是只能出现一次或0次,若是在字段声明前加上repeated的话就能够出现屡次。

protobuf的标量类型有如下几种:double float int32 int64 uint32 uint64 sint32 sint64 fixed32 fixed64 sfixed32 sfixed64 bool string bytes

protobuf中还可使用枚举和复合类型。例如能够经过import "google/protobuf/timestamp.proto"来使用timestamp类型。

protobuf数据类型的默认值规则以下,若是一个字段被设置为默认值,则其不会被序列化:

  • string bytes类型默认为空
  • bool类型默认为false
  • 数值类型默认为0
  • 枚举类型默认为第一个,即0
  • 复合类型取决于语言

枚举类型

message SearchRequest {
  enum Corpus {
    option allow_alias = true;
    UNIVERSAL = 0;
    WEB = 1;
    TEST = 1;
    IMAGES = 2;
  }
  Corpus corpus = 4;
}

经过enum来声明一个枚举,注意枚举中必需要有0值用来做为默认值,同时0值应该是第一个元素,以与proto2兼容。经过option allow_alias = true;来容许两个枚举元素有相同的值,即这两个元素能够相互替代。

复合类型

在一个message中,能够嵌入其余的message做为复合类型:

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}

protobuf中还有其余高级类型,如Any oneof map等,就不详细介绍了。

相关文章
相关标签/搜索