GRPC從使用到深入--Protocol Buffers的理解

一.Protocol Buffers應用場景

1.序列化的應用場景

PB要解決的是序列化的問題,所以我們從序列化的角度去理解PB。

序列化就是將一個數據結構(通常是對象)轉換爲二進制的行式。

反序列化則是將二進制數據轉換爲數據結構或對象。

因爲在內存中最容易處理的數據行式是對象,而在存儲和通信時最容易處理的是二進制數據,因此在面臨存儲對象和傳輸對象的場景時,就會需要解決序列化和序列化的問題。

就像ORM解決面向對象和關係數據庫的匹配問題一樣,序列化也是解決面向對象和存儲/通信的匹配問題。

2.序列化面臨的問題

2.1.定義目標對象

此步驟包括兩個問題:1.定義哪些對象可以被序列化; 2.定義對象的哪些字段可以被序列化

假設我們要實現一個自定義協議,報文和通信部分都要自己完成. 那麼其實報文的組裝和解析就是一個序列化/反序列化的過程

此時,比較簡單的實現,就是讓需要序列化的對象實現以下接口

interface ICode_Decode {
    byte[] serialize(object o);
    Objcec deSerialize(byte[] bytes);
}

這種解決方式對於個性化的序列化要求比較適用,但是對於通用的序列化則不太現實,因爲不可能讓所有需要序列化的對象都實現一遍這兩個方法.

所謂通用的序列化,就是把對象理解爲由一系列屬性名--屬性值組成的Key--Value對.

①JDK和.net Framework對於對象的序列化都有其內部的實現。大致的實現方式都是通過接口或者特性來對類及其字段進行標註,然後進行序列化,因爲都是自帶的內部實現,因此這些實現對類本身的特性很熟悉,序列化時會有各自語言特有的內容。

②跨平臺的XML和json序列化實現。

③根據配置文件生成類。即Protocol Buffers的實現。

syntax = "proto3";
package mypackname;

option java_package "org.feng.wildland";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
  Corpus corpus = 4;
}

enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }

以上文件即爲.proto的一個示例,通過代碼生成工具,將會生成 org.feng.wildland.mypackagename.SearchRequest的類,並生成相應的用於序列化的方法。

2.2編碼方式

①如XML和Json,字符串的編碼方式

②二進制的編碼方式

通常生成的json字符串是自包含的。但是pb不是。

pb序列化後的數據中不包括變量名,而只有變量編號,即.proto文件中每個變量後面定義的數字

pb編碼後,第一個字節包括變量編號+變量類型,後面是變量的值;如果變量類型爲不定長的類型,那麼第二個字節是變量長度。

2.3版本號問題

我們的代碼時不斷迭代更新的,那麼爲對象添加刪除字段也是很正常的事情。

①java中需要序列化的類需要添加private static final long serialVersionUID ,如果反序列化時,發現該字段不一致,則報錯,如果該字段一致,但是新添了字段,那麼該字段設置爲默認值;

@Protocol Buffers中,沒有 版本號的概念。在更新了代碼後,再反序列化,會遇到以下情況

如果新添了字段,則該字段爲默認值;如果新添了repeat 類型字段,則爲空

如果刪除了字段,則爲不可識別的字段

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章