This page looks best with JavaScript enabled

Protobuf and Json

 ·  ☕ 2 min read

protobuf vs json

最近工作新專案要把原有的 http request 和 response 都從 json 改為 protobuf
預期是可以讓網路傳輸量還有 (de)serialize 加速~

所以這邊想研究一下 protobuf 到底是做了什麼才比 json 快

json

基本上 json 就是一串字
例如我們操作的 object:

{
    "key": "value"
}

轉成字串和bytes就是這樣

{"key":"value"} 

7b 22 6b 65 79 22 3a 22 76 61 6c 75 65 22 7d

傳輸的時候就是把這串 byte 傳過去,包括 {} "" 都算,大約是 15 bytes

而且 deserialize 的時候都是要掃過那個字串的每一個字,判斷每個字是符號還是數字等等,才能轉換成程式語言裡面的 object,很耗時

protobuf

使用 protobuf 來溝通前 client server 要先定義好溝通的格式 .proto 檔案
例如

syntax = "proto3";

message Data {  
    string key = 1;
}

client 和 server 都會使用這個檔案來產生對應的語言的資料結構
像是 Go 會產生
xxx.pb.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
type Data struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Key       string `protobuf:"bytes,1,opt,name=key,proto3"`
}

func (x *Data) GetKey() string {
	if x != nil {
		return x.Key
	}
	return ""
}

當收到一串 byte 時,使用 proto.Unmarshal 就可以把 byte 轉回 struct 了

Why protouf is more efficient than json

.proto 檔案每個 field 後面都會有個數字,在傳輸時會替代 field name

到達目的地時對方在使用先前定義好的 proto 來查詢數字對應的 field name,可以省下很多空間

除此 field name 的替換外,protobuf 在內容上也會有編排過讓傳輸與 parse 更有效率
以下舉個例子

例如傳送 string 時就會加上長度的資訊
我們用上面的 .proto 為格式傳送了

{
    "key": "abc"
}

那實際上傳出去的 bytes 會是

09 03 61 62 63

第一個 byte 0x09
可以拆解成 00001 010
前 5 個 bits 00001 代表的是 field name number
後 3 個 bits 010 代表的是 string type
原先的 “key” 卻要佔用 5 個 bytes,這邊只要 1 個而已


第二個 byte 0x03 代表了長度
後面接著 61 62 62 就是內容
如此一來在 deserialize 時就可以直接以 data[i:i+3] 這種方式抓出資訊
不用像 json 一樣每個字元都判斷,當長度很長時差距會很大

再舉個傳輸 integer(Varint) 的例子
如果數字是 300 的話,實際上傳送的資料會是
1010 1100 0000 0010

每個 byte 的 most significant bit 用來代表下一個 byte 還是不是資料,如果是 1 的話代表下一個 byte 也要一起計算

將第一個 bit 去掉之後然後兩個 byte reverse (因為儲存方式是 least significant group first)
_000 0010 _010 1100

就可以得到 300 了

而 json 在傳送時每個字元都代表了一個 byte,在數字大的時候資料量差距也很大

總結與優缺點

前面舉了一些例子來說明 protobuf 的設計是如何讓它更有效率
field name number 如何省資料量
string 如何讓 parse 更快
integer 如何省資料量
還有省掉了符號 {} , : 的資料量
應該還有其他的但就不一一列舉

總之使用 protobuf 對我們的程式處理資料都會有效率很多
而資料內容在處理前是人類不可讀的(有好有壞)

目前從使用 json 轉換到 protobuf 後感覺多了一些開發成本,畢竟前後端都習慣用 json 來做事情,多了一個東西要管,大家都要熟悉才行
如果開發的東西規模不大,資料量不大的話還是從 json 開始使用避免額外成本過高

Ref: https://developers.google.com/protocol-buffers/docs/encoding

Share on

Marko Peng
WRITTEN BY
Marko Peng
Good man