系統會滾動升級,所以新舊版程式碼、新舊格式資料一定會同時並存。編碼格式選得好不好,決定你能不能一邊部署一邊不出事——關鍵是雙向相容。
🧠 Core Ideas
TIP
兩個方向都要顧:向後相容=新程式碼讀得懂舊資料;向前相容=舊程式碼讀得懂(並忽略)新資料。向前相容比較難,因為要讓舊碼安全跳過它不認識的東西。
- 記憶體物件 ↔ 位元組序列的轉換就是 編碼 / 解碼(serialization / parsing)。
- 為什麼一定會並存:伺服器滾動升級、客戶端各自更新,不可能一次到位。
- 一句話原則:資料的壽命比程式碼長(data outlives code)——碼幾分鐘就換掉,資料放五年。
⚖️ Tradeoffs
三類格式,一條相容性光譜
- 語言內建(Java Serializable、pickle):綁單一語言、有安全風險、相容性差 → 只適合極短暫用途,別拿來持久化或跨服務。
- 文字格式(JSON / XML / CSV):人類可讀、跨語言、最適合組織間交換;但數字有模糊性(JSON 不分整數/浮點,>2⁵³ 會掉精度)、二進位要 Base64(+33%)、schema 支援參差。
- 二進位 schema 格式(Thrift / Protocol Buffers / Avro):組織內部首選——更小、更快、相容語義明確、schema 兼作文件與程式碼生成。
Protobuf / Thrift — 靠「欄位標籤」做演進
- schema 給每個欄位一個數字標籤;編碼只放標籤不放欄位名 → 小很多。
- 演進規則(背下來):
- 可以改欄位名(編碼裡只有標籤);不能改標籤(一改舊資料全失效)。
- 新增欄位用新標籤,且必須 optional 或有預設值(否則破壞向後相容)。
- 移除只能移 optional 欄位,且標籤永不重用。
Avro — 沒有標籤,靠 writer/reader schema 對齊
- 編碼只有值、連欄位名/標籤都沒有 → 最緊湊(範例 32 bytes vs Protobuf 33、JSON 81)。
- 核心:寫入者 schema 與讀取者 schema 不必相同、只要相容,函式庫用欄位名自動對齊差異(多的忽略、缺的補預設)。
- 可選欄位用 union(如
union{null,long})+ 預設值,強迫你明講哪些能為 null。 - 沒有標籤 → 特別適合從資料庫 schema 動態生成,改 schema 不用手動維護標籤對應。
三種資料流的相容性責任
- 經資料庫:寫入者編碼、讀取者解碼;小心舊碼讀到新欄位、寫回時把它弄丟(要保留未知欄位)。
- 經服務(REST/RPC):一般伺服器先升 → 請求要向後相容、回應要向前相容;跨組織時得長期維護多個 API 版本。
- 經非同步訊息:透過 broker 傳位元組,只要編碼支援雙向相容,publisher / consumer 就能各自獨立升級。
🔑 Takeaways
- 滾動升級 = 新舊並存,所以向後 + 向前相容是編碼選型的第一考量。
- 跨組織用文字格式(JSON)好談;組織內用 Protobuf/Avro 換緊湊與明確的演進規則。
- 演進鐵律:標籤不改、新欄位可選、移除欄位不重用標籤;資料的壽命比程式碼長,schema 要能演化。
No notes yet — jot your takeaways or Q&A here.