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等,就不詳細介紹了。

相關文章
相關標籤/搜索