在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
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
等,就不详细介绍了。