iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 15
1
AI & Data

資料工程師修煉之路系列 第 15

[Day 15] Encoding and Evolution(3) - Thrift and Protocol Buffers

  • 分享至 

  • xImage
  •  

接續 Day 14

Thrift and Protocol Buffers

再來要講的 binary encoding 工具就是 Apache ThriftProtocol Buffers (protobuf),Protocol Buffers 是 Google 開發的,Thrift 是 Facebook,它們的概念差不多,都是需要為資料額外定義 schema,一樣繼續使用這份 JSON 資料來說明:

JSON Example 4-1

{
    "userName": "Martin",
    "favoriteNumber": 1337,
    "interests": ["daydreaming", "hacking"]
}

然後 Thrift 的 schema 長這樣:

struct Person {
  1: required string userName,
  2: optional i64 favoriteNumber, 
  3: optional list<string> interests
}

Protocol Buffers 的話類似長這樣:

message Person {
	required string user_name = 1; 
	optional int64 favorite_number = 2; 
	repeated string interests = 3;
}

Thrift 跟 Protocol Buffers 都有程式碼產生工具 (code generation) 來產生不同程式語言的程式,你的系統只要呼叫產生好的程式做 encode 和 decode,Thrift 有 2 種不同的 binary encoding 格式,為 BinaryProtocolCompactProtocol,首先就來看 BinaryProtocol 的結果吧,大小為 59 bytes,

figure_4-2

看起來跟昨天講到的 MessagePack encoding 結果很像,第一個位元組是欄位型態,再來 2 個位元組是 欄位標籤 (field tag),再來的 4 個位元組說字串長度為 6,然後接下來 6 個位元組就是用 ASCII 編碼後的位元組 Martin ,以此類推,

這裡可以看到最大不同的是 Thrift 沒有存欄位名稱 (userName, favoriteNumber, interests),光這一點就省下不少空間了,取而代之的是用 欄位標籤 (field tag) 來當作欄位別名,

然後 Thrift 的下一個格式 CompactProtocol encoding 結果跟 BinaryProtocol 類似,如下圖 4-3,大小為 34 位元組,最大的不同是 CompactProtocol 把欄位型態跟欄位標籤併成一個位元組,另一個就是使用可變動大小的位元組來表示數字,例如一個位元組能表示 -64 ~ 63 的數字,2 個位元組能表示 -8192 ~ 8191 的數字,所以 1337 就只被寫成 2 個位元組,而不是 i64 這個整數型態的完整 8 個位元組。

figure_4-3

最後來看 Protocol Buffers,它只有一種 binary encoding 格式,encoding 的結果大小為 33 位元組:

figure_4-4

Thrift 跟 Protocol Buffers schema 的每個欄位都能設 requiredoptional ,皆是在執行時才會做檢查,以利幫助工程師找 bug。

最後要來看,若 schema 會隨著時間改變,Thrift 和 Protocol Buffers 如何保持 Day 13 講過的向前和向後兼容能力呢?

schema 演進 - 欄位標籤 (field tags)

欄位標籤 (field tags) 對 Thrift 和 Protocol Buffers 是不能隨意修改,但欄位名稱沒這麼重要,可以隨時改,

初始版本的 schema 確定後,新增欄位時務必要把新欄位設定為 **optional **或給他 初始值,因為:

  • Backward compatibility (向前兼容) - 新程式要能讀舊程式寫入的資料

    非 required 的情況下新程式舊資料時會忽略新欄位。

  • Forward compatibility (向後兼容) - 舊程式要能讀新程式寫入的資料

    若把新欄位設 required ,舊程式讀到新程式寫入的資料時就爆炸了。

刪除欄位也是一樣道理, 欄位標籤不變的情況下你只能移除 optional 的欄位,然後你 不能再使用一樣的欄位標籤

schema 演進 - 欄位型態 (data types)

你可以把 32-bit 的整數改成 64-bit 整數,因為新程式再讀舊資料時會補足不足的位元,但舊程式在讀新資料時會爆掉,其他的欄位型態改變可參考官方文件。

另一個可以改變型態的是 Protocol Buffers 的 repeated 型態 repeated string interests = 3;,它能把單一值變多值,Protocol Buffers 沒有 list 或 array 的資料型態,取而代之的是 repeated ,表示這欄位會出現多次,所以你可以把 optional 改為 repeated,舊程式讀新資料時只會用最後一筆的資料,新程式讀舊資料時會視為長度為 0 或 1 的 list。

雖然 Thrift 沒有這個好處,但它的 list 型態就能支援巢狀結構。


以上,明天就來講 Avro 吧(最近應該會因為中秋連假而會有連假版本文章 XD)


上一篇
[Day 14] Encoding and Evolution(2) - Json, XML, CSV 和 Binary variants (二進制變體)
下一篇
[Day 16] Encoding and Evolution(4) - Avro
系列文
資料工程師修煉之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言