「阅读」数据密集型系统设计 第四章 编码

embedded/2024/9/25 3:18:39/

第四章 编码和演化

一、为什么需要考虑编码?

在大型应用程序中,代码变更无法立刻生效。原因如下:

  • 服务端程序:代码往往通过灰度发布方式,新版本主键部署到所有节点
  • 客户端程序:取决于用户是否更新
    上述过程意味着,新旧数据格式会在系统中共存,系统顺利运行的前提是 双向兼容,即:
  • 向后兼容:新的代码可以读取旧代码写入的数据
  • 向前兼容:旧的代码可以读取新代码写入的数据

本章中介绍几种编码数据格式:JSON、XML、Protocol Buffers Thrift 和 Avro。重点关注:这些格式如何应对模式变化,如何对新旧代码数据需要共存的系统提供支持。

最后,本章介绍了如何使用数据进行存储和通信:REST、RPC、消息传递系统

大体上说,文章中提到的模式演变是指在系统迭代过程中,对接口的参数进行修改(例如 IDL 中定义了接口的模式,对 IDL 的修改就代表了文中说的模式转变)

一般来说,大型系统中为了兼容旧数据,不会修改现在正在使用的字段的类型或者将一个字段从可选转为必须,更多的是增加新的字段。

二、编码格式

程序通常有两种形式的数据:

  1. 在内存中,数据保存在对象,结构体,列表,数组,哈希表,树等中。 这些数据结构针对CPU的高效访问和操作进行了优化(通常使用指针)。
  2. 如果要将数据写入文件,或通过网络发送,则必须将其 编码(encode) 为某种自包含的字节序列(例如,JSON文档)。 由于每个进程都有自己独立的地址空间,一个进程中的指针对任何其他进程都没有意义,所以这个字节序列表示会与通常在内存中使用的数据结构完全不同。

所以

  1. 编码:内存中表示从对象等转换为字节序列的过程成为编码
  2. 解码:编码的反过程

2.1 文本格式 json xml csv

文本格式编码的一个特点就是:具有很好的可读性并且跨平台性,但是这些文本格式也有一些问题

  • 数字处理
    • xml csv 中,无法区分数字和由数字组成的字符串
    • json 无法区分整数和浮点数,不可以指定精度
  • 二进制数据
    • json xml 不支持二进制数据
  • 模式
    • xml json 提供的模式支持功能强大但是实现复杂
    • csv 没有模式,每行每列含义均由应用程序确定,非常模糊

2.2 二进制编码

二进制编码的最大优势:占用空间小,效率高。

thrift 和 protocol buffers

两者是基于相同原理的二进制编码库,它们的构成如下:

  • 通过 IDL (接口描述语言)描述模式
  • 通过代码生成工具,生成不同编程语言的类

如何处理模式演变?

  1. 字段标签部分
    1. 添加新字段:
      1. 向前兼容:
      2. 可以添加新字段,必须具有新的标记号码
      3. 为了保证向后兼容,处理时必须有以下两种准则
        1. 标记为可选参数
        2. 一定会有默认值
    2. 删除字段:
      1. 只能选择可选字段
      2. 不能使用当前的 标签号码(这个在 thrift 中似乎做不到?)
  2. 数据类型部分
    1. 数据类型可以改变(int32-int64)
      1. 向后兼容
        1. 满足,新代码可以读旧代码的数据
      2. 向前兼容
        1. 不满足,读取会截断
    2. Protobuf:没有列表类型,只有 repeated,因此可以把可选字段改为重复字段
    3. Thrift 不可以更改为参数列表,优点是可以嵌套列表。
Avro

Avro 是另一种二进制编码格式
Avro 中有两种模式语言:Avro IDL && JSON

IDL
record Person {string                userName;union { null, long }  favoriteNumber = null;array<string>         interests;
}JSON
{"type": "record","name": "Person","fields": [{"name": "userName", "type": "string"},{"name": "favoriteNumber", "type": ["null", "long"], "default": null},{"name": "interests", "type": {"type": "array", "items": "string"}] 
}

Avro 中关键思想是:Writer 模式和 Reader 模式不必完全相同,只需要兼容。

模式演变规则:

  • 为了兼容性,只能添加或者删除具有默认值的字段。

2.3 不同编码选型

  1. 公司内部系统间调用,性能要求 100ms 以内,可以考虑基于 XML 的 SOAP 协议
  2. 性能要求不高,或者数据负荷较小的,可以选择 JSON
  3. 性能要求较高,Protobuf Thrift Avro 均可
  4. 如果需要提供完整的 RPC 能力,选择 Thrift
  5. 如果对持久性要求在 T 级别,Protobuf 和 Avro 首选
  6. 序列化需要支持不同传输协议,优先考虑 Protobuf

三、数据流类型

数据流动的常见方式

  • 数据库
  • 服务调用
  • 异步消息传递

3.1 数据库中的数据流

解码:读取数据库
编码:访问数据库

场景描述:

多个服务访问同一个数据库,其中服务a对数据行字段进行扩展,则服务b对行进行读写时,要保证仅对旧字段进行更新,不能影响新字段的值

3.2 服务中的数据流

RPC 的问题

  • 远程调用会存在网络超时导致的没有结果返回,如何处理?
  • 网络请求的时间相较于本地函数调用是不稳定的
  • 超时失败,客户端进行重试时,服务端如何保证幂等?
  • 通过网络,如何传递对象

RPC 和数据编码

  • RPC 可能会使用上述编码格式中的任何一种,模式演化时是否能支持向前/后兼容,需要取决于编码格式

3.3 消息传递中的数据流

消息传递:不通过直接的网络连接发送信息,而是通过消息代理中介临时存储信息。

和 RPC 相比,消息传递的通信是单向的。

消息代理的使用方式如下:

  • 一个进程将消息发送到指定的队列/主题
  • 代理确保消息传递到订阅主题的消费者

消息代理通常不会执行特定的数据模型,可以使用任何编码。


http://www.ppmy.cn/embedded/94295.html

相关文章

[论文翻译] LTAChecker:利用注意力时态网络基于 Dalvik 操作码序列的轻量级安卓恶意软件检测

LTAChecker: Lightweight Android Malware Detection Based on Dalvik Opcode Sequences using Attention Temporal Networks 摘要&#xff1a; Android 应用程序已成为黑客攻击的主要目标。安卓恶意软件检测是一项关键技术&#xff0c;对保障网络安全和阻止异常情况至关重要。…

基于大数据的气象数据分析与可视化系统设计与实现【爬虫海量数据,LSTM预测】

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍研究目的研究意义研究思路可视化展示每文一语 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 本课题主要针对气象数据进行分析以及可视化…

在一串字符串中Java使用正则匹配电话号码的方法

1.使用正则表达式来匹配电话号码 在Java中&#xff0c;使用正则表达式匹配电话号码是一个常见的需求。电话号码的格式可能因国家/地区而异&#xff0c;但一个典型的格式可能是这样的&#xff1a;(123) 456-7890。在这个例子中&#xff0c;我将提供一个Java程序&#xff0c;该程…

立体相机镜面重建(二)双目立体镜面重建

使用双目相机&#xff0c;配合镜子、屏幕&#xff0c;可以直接获得镜面的三维数据&#xff0c;无需先验知识。因此使用双目镜面重建方式对镜子表面进行重建。 &#xff08;一&#xff09;重建步骤 使用左相机光线法来计算镜面点&#xff1a; 1.取一个像素点&#xff0c;计算其…

【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】017 - init_sequence_f 各函数源码分析(一)

【OpenHarmony4.1 之 U-Boot 2024.07源码深度解析】017 - init_sequence_f 各函数源码分析(一) 一、setup_mon_len():配置 gd->mon_len 监控长度二、fdtdec_setup() :设备树初始化,配置 gd->fdt_blob 指向uboot镜像末尾的 device tree三、【RK3568未跑】trace_early…

Python 在开发中的设计模式有哪些?怎样使用?

大家好&#xff01;我是爱摸鱼的小鸿&#xff0c;关注我&#xff0c;收看每期的编程干货。 今天我们要聊点硬核的——设计模式。不过&#xff0c;不用担心&#xff0c;我会带着热情来跟你分享这些看似枯燥的知识点。让我们一起从“代码搬砖工”蜕变成“代码艺术家”吧&#xff…

常见8种数据结构

常见的数据结构包括数组、链表、队列、栈、树、堆、哈希表和图&#xff0c;每种数据结构都有其特点&#xff0c;如下&#xff1a; 常见数据结构 1.数组2.链表3.队列4.栈5.树6.图7.哈希表8.堆 1.数组 特点&#xff1a; 固定大小的线性数据结构支持快速随机访问插入和删除效率…

代码随想录算法训练营Day35||01背包

一、01背包 &#xff08;1&#xff09;dp数组定义&#xff1a;当目前背包容量为j时&#xff0c;从第0件物品遍历到第i件物品的最大价值 &#xff08;2&#xff09;递推公式&#xff1a;dp[i][j]dp[i-1][j]&#xff08;一定装不下第i件物品&#xff0c;即j<weight[i]时&#…