Proto 序列化不是標準格式
說明序列化如何運作,以及為何它不是標準格式。
許多人希望序列化的 proto 能以標準格式表示該 proto 的內容。使用案例包括
- 將序列化的 proto 用作雜湊表中的鍵
- 取得序列化 proto 的指紋或檢查總和
- 比較序列化的酬載,作為檢查訊息相等性的一種方式
遺憾的是,protobuf 序列化不是(且無法成為)標準格式。有一些值得注意的例外,例如 MapReduce,但一般來說,您應該將 proto 序列化視為不穩定。本頁說明原因。
決定性不是標準格式
決定性序列化不是標準格式。序列化程式可能會因許多原因產生不同的輸出,包括但不限於以下變更
- protobuf 結構描述以任何方式變更。
- 正在建置的應用程式以任何方式變更。
- 二進位檔是以不同的標記建置(例如 opt 與 debug)。
- protobuf 程式庫已更新。
這表示序列化 proto 的雜湊值是脆弱的,且無法跨時間或空間穩定。
序列化輸出可能變更的原因有很多。以上清單並未詳盡列出。其中有些是問題空間中固有的困難,即使我們想要保證標準序列化,也會使其效率低下或不可能。其他則是我們刻意保留未定義的事項,以允許最佳化機會。
穩定序列化的內在障礙
Protobuf 物件會保留不明欄位,以提供向前和向後相容性。不明欄位無法以標準格式序列化
- 不明欄位無法區分位元組和子訊息,因為兩者具有相同的連線類型。這使得無法將儲存在不明欄位集中的訊息標準化。如果我們要標準化,就需要遞迴到不明子訊息中,依欄位編號排序其欄位,但我們沒有足夠的資訊來執行此操作。
- 為了效率,不明欄位始終在已知欄位之後序列化。但標準序列化需要依欄位編號將不明欄位與已知欄位交錯。即使是不使用此功能的人,也會導致效率和程式碼大小負擔。
刻意保留未定義的事項
即使標準序列化是可行的(也就是說,如果我們可以解決不明欄位問題),我們仍刻意保留未定義的序列化順序,以允許更多最佳化機會
- 如果我們可以證明欄位永遠不會在二進位檔中使用,則可以從結構描述中完全移除該欄位,並將其作為不明欄位處理。這可以節省大量的程式碼大小和 CPU 週期。
- 可能有機會透過將相同欄位的向量一起序列化來進行最佳化,即使這會破壞欄位編號順序。
為了為此類最佳化保留空間,我們希望在某些組態中刻意混亂欄位順序,以便應用程式不會不適當地依賴欄位順序。