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 类型字段,则为空

如果删除了字段,则为不可识别的字段

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