Part 1 编码
内存中的数据可以有多种格式,但是如果要传输或者写到磁盘,就需要编码(序列化)成字节序列。
由于服务端会升级,所以需要保证读写数据的代码有兼容性,包括:
- 前向兼容,旧代码可以读新数据
- 后向兼容,新代码可以读旧数据
1 语言内置编码
很多编程语言内置了将内存对象编码为字节序列的方法,但是有如下缺陷:
- 和编程语言绑定
- 安全问题,解码从字节序列实例化任意一个类,利用这一点可以运行危险代码
- 兼容性和效率
2 XML JSON CSV
标准化编码,缺陷:
- XML和CSV不能区分数字和字符串(除非引用外部模式)。 JSON虽然区分字符串和数字,但不区分整数和浮点数,而且不能指定精度
3 二进制编码
3.1 JSON 二进制格式
存储如下信息:
{
"userName": "Martin",
"favoriteNumber": 1337,
"interests": ["daydreaming", "hacking"]
}
JSON 格式表示上述信息需要 88 字节。MessagePack 是一种 JSON 二进制编码格式,编码如上信息共需要66字节。

可以看到,MessagePack 在编码时需要将诸如 “userName” 这样的 key 编码进去,但实际上如果发送端和接收端约定好了 key ,这些信息是不需要传输的。预先约定好的文档信息可以称之为约束文档,元信息等等,以下编码方式均是基于此种方式的。
3.2 Thrift
struct Person {
1: required string userName,
2: optional i64 favoriteNumber,
3: optional list<string> interests
}
分为 Thrift 二进制协议和 Thrift 压缩协议,可以压缩至 34 字节

3.3 pb
message Person {
required string user_name = 1;
optional int64 favorite_number = 2;
repeated string interests = 3;
}
同样压缩到 33 字节

3.4 XML 二进制格式
EXI with schema,基于约束文档(通常是 XSD ,XML Schema Document)的 EXI 编码。
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="100"/>
</xs:restriction>
</xs:simpleType>
EXI 使用 schema 基于这样一个理念,在对一个文档进行编码之前,如果预先知道这个文档长什么样子(字段名称、数据类型、数值范围等等),可以更快更好地压缩编码,描述文档的文档可以称之为约束文档(schema),EXI 的约束文档比 pb thrift 内容更加丰富
3.5 schema evalution 模式演变
schema
schema 模式,文档,约束文档
schema 可能发生变化,要考虑兼容性
修改字段
- 可以更改字段名称,但不能更改字段标签
- 增加字段
旧代码读新数据,忽略超出范围的字段标签,保证前向兼容;
新代码读旧数据,增加的字段必须为可选的或者有默认值,保证后向兼容 - 删除字段
旧代码读新数据,删除的字段必须为可选的
新代码读旧数据,忽略删除的字段,且该字段的标签不能再使用
改变数据类型
例如32位变为64位,旧代码读新数据时可能产生截断
repeated of pb
Thrift 有 list 类型,PB 没有表示数组的类型,而是用 repeated 表示
优势在于:单一值改为 repeated ,新代码读旧数据,不影响,旧代码读新数据,只能读到一条,但不会出错(Thrift 会出错)
3.5 Avro
record Person {
string userName;
union { null, long } favoriteNumber = null;
array<string> interests;
}
字节数最少,32字节

特殊性:
- 没有字段标签,读取数据必须与写入数据使用完全相同的模式才可以正确解析
- 为了保持兼容性,只能添加或删除具有默认值的字段
- 没有字段标签,适合动态生成 schema 的使用场景,例如从数据库转储数据,如果让 pb 或 thrift 来做,在数据库变更时(删除一列)需要手动生成字段标签
Part 2 数据流
数据流
数据在不同进程间流动,数据流,通常有三种形式
- 数据库
- 服务调用 rest rpc
- 异步消息传递
数据库
数据存储在数据库中

需要考虑兼容性
服务调用
WEB 服务
底层使用 HTTP 协议进行交互的服务都可以称之为 Web 服务
SOAP vs REST
Web 服务编程,REST 与 SOAP
SOAP 以操作为中心(靠近 RPC),REST 以资源为中心
RPC
RMI 仅限于 Java , DCOM 仅限于 Microsoft , CORBA 过于复杂没能普及
RPC 面临的问题:
- 本地函数调用要么成功,要么失败,要么不返回(陷入死循环),远程函数调用存在另一种情况,由于网络阻塞等原因超时,不知道是否执行成功;
- 网络时延变化的,不确定;
- 传参,需要将参数对象编码成字节序列
异步消息传递
异步消息传递介于 RPC 和数据库之间。它们与RPC类似,因为客户端的请求(通常称为消息)以低延迟传送到另一个进程。它们与数据库类似,不是通过直接的网络连接发送消息,而是通过称为消息代理 Message Broker(也称为消息队列 Message Queue 或消息中间件)的中介来临时存储消息。异步消息传递是异步、单向的。
优点:
- 如果接收方不可用或过载,可以充当缓冲区,从而提高系统的可靠性
- 订阅发布机制,允许允许将一条消息发送给多个接收方
- 面向数据,将发送方与接收方分离
本文是DDIA读书笔记的一部分,聚焦于数据编码,对比了语言内置编码、XML/JSON/CVS与二进制编码的优缺点。重点讨论了二进制编码的JSON二进制格式(如MessagePack、Thrift、protobuf)、XML二进制格式(如EXI)以及Avro的特性,强调了编码中的兼容性问题和模式演进策略。
1722

被折叠的 条评论
为什么被折叠?



