Skip to main content

Ch4: 資料編碼與演化

如何更新軟體

  • 伺服器端: 滾動升級
  • 客戶端: 使用者自己決定時機
  • 資料庫
    • 在 NoSQL 中,可以同時接受新舊資料格式
    • 在關聯式資料庫中,任何時間點只有一個 schema 有效

相容性

回朔相容 (Backward compatibility) 較新的程式碼可以讀取由舊程式碼所寫入的資料 <-- 比較簡單

向前相容 (Forward compatibility) 較舊的程式碼可以讀取由新程式碼所寫入的資料 <-- 預測未來

資料編碼格式

程式至少使用兩種表示資料的格式:

  1. 在記憶體中
  • object
  • struct
  • list
  • array
  • hash table
  • tree
  1. 不在記憶體中,例如檔案、網路傳輸,必須是某種 self-contained 的位元組序列
  • JSON
  • XML
  • CSV

在這兩種之間轉換的動作稱之為編碼 (encoding, serialization, marshalling) 和解碼 (decoding, deserialization, unmarshalling) 。

JSON, XML, CSV 的缺陷

  • XML 和 CSV 無法區分字串和數字
  • JSON 無法區分整數和浮點數,也無法指定精度,固定使用 IEEE 754
  • JSON 和 XML 不支援二進位字串 (CSV 可以?)
  • XML 和 JSON 可以定義 schema,而 CSV 不行
Base64 編碼

Base64 編碼將二進位資料轉為字串,但是會增加約 33% 的大小

JSON 使用 IEEE 754 的限制

在某個應用場景,需要儲存精準到奈秒的時間戳,但 IEEE 754 的最大整數範圍到 2^53 -1,完全存不下,只好使用字串表示

  • 2^53 - 1
    • 9,007,199,254,740,991
  • current epoch time in nano second
    • 1,713,578,589,000,000,000

二進位編碼

犧牲了可讀性,換取更短的編碼長度及更快的解碼速度。

以此 JSON 文件用於後續的二進位編碼對照範例

{
"userName": "Martin",
"favoriteNumber": 1337,
"interests": ["daydreaming", "hacking"]
}
FormatDeveloperSize in bytesExtra schema
JSON (without spaces)JavaScript (2001)81No
MessagePackSadayuki Furuhashi (2008)66 (81%)No
Thrift BinaryProtocolFacebook (2007)59 (72%)Yes
Thrift CompactProtocolFacebook (2007)34 (41%)Yes
Protocol BuffersGoogle (2008)33 (40%)Yes
AvroApache Hadoop (2009)32 (39%)Yes

省略了特殊符號 { } [ ] " ,,取而代之的在每個欄位前面用 1 個 byte 表示型態和長度。

另外,把數字轉成 16 進位也稍微縮短了長度 (1337 在 10 進位用 4 bytes,在 16 進位只用 2 bytes) 。

fig4.1

Schema 演化時的相容性

  • 新增和刪除的欄位必須是選填的,否則舊版 schema 會無法讀取 (無法回朔相容)
  • 不可以刪除必填欄位,而且該欄位編號不能再被其他欄位使用

Dataflow 模式 資料傳輸模式

透過資料庫

常見的情況

  • 只有一個存取資料庫的程式,而讀取方式同一隻程式的較新版,可以看作「向未來的自己發送訊息」
  • 多個不同的程式同時存取資料庫,有些程式版本較新,有些則較舊。例如,系統正在進行滾動升級
    • 舊版程式可能會不小心丟失新版程式寫入的資料

歸檔儲存

對資料庫做快照 (snapshot) 時,或許會將其存入存儲服務 (AWS S3) 或資料倉儲 (data warehouse)

  • 使用 Avro 將檔案格式放在此快照的開頭處是個好選擇,使其自我描述 (self contained)
  • 將資料編碼成行式儲存 (column based) 的好機會,如 Parquet 格式,更容易用在資料分析上

透過網路服務: REST 和 RPC

  • REST: 基於 HTTP 的一種設計哲學
  • SOAP: 使用一種基於 XML 的語言 WSDL (Web Services Description Language) 來描述其 API
    • WSDL 產生的 SOAP 訊息通常複雜到難以靠手動產生,也很難閱讀,因此漸漸的不受大眾喜愛
  • RPC (Remote Call Procedure): 試圖使向遠端網路服務發出請求,就像在同一程式中呼叫函數一樣 (稱為位置透明性,localtion transparency)
    • 網路請求是不可預測的,當請求逾時的時候,沒辦法確認到底執行了沒
      • 若函數具有冪等性 (idempotence) ,那就可以發出多次請求,而不用擔心引發額外的問題
    • 呼叫本地函數時,可以直接傳遞參數的參照 (指標) ,而如果是透過網路傳輸,問題就複雜的多

透過非同步訊息

雙方透過一種稱為訊息代理 (message broker) 的中介軟體來溝通,也稱為訊息佇列 (message queue) 或是訊息導向的中介軟體 (message-oriented middleware) 。

  • 當接收方離線或是超載時,可以當作緩衝區,提高系統的可靠性
  • 自動將訊息重發到之前發生崩潰的程式,防止訊息遺失
  • 發送方不需要知道接收方的資訊 (IP, 實作等等) ,降低耦合
  • 一條訊息可以發送給多個接收方
  • 訊息內容可以使用任何的編碼格式,只是要記得思考回朔與向前相容

小結

  • 在滾動升級期間,必須假設不同節點上正執行著不同版本的程式,因此必須保證在系統內傳輸的資料以回朔相容和向前相容的方式進行編碼

    • 回朔相容: 新程式可以讀舊資料
    • 向前相容: 舊程式可以讀新資料
  • 資料編碼格式

    • JSON, XML, CSV 很常見也好使用,但是有其限制
    • Thrift, Protobuf, Avro 能以定義的 schema 完成緊湊、高效率的編碼,但在解碼前毫無可讀性
  • 資料傳輸模式

    • 資料庫: 寫入資料庫的程式負責編碼,讀取資料庫的程式複雜解碼
    • REST API 和 RPC: 客戶端將請求編碼,伺服器端將請求解碼後處理,再將回應編碼,客戶端收到後再解碼
    • 非同步訊息: 發送方編碼訊息,由接收方解碼
info

只要用心,系統一定可以實現回朔/向前相容!

fig4.6