ch1-ch3

1.5K
0
0
最后修改于

Ch1#

开篇老生常谈的可靠性,可伸缩性,可维护性

大部分应用是数据密集型应用。
需要的数据组件包括但不限于:

  • 数据库
  • 缓存
  • 搜索索引
  • 异步处理
    • 流处理
    • 批处理

存储数据,以便自己或其他应用程序之后能再次找到 (数据库(database))记住开销昂贵操作的结果,
加快读取速度(缓存(cache))允许用户按关键字搜索数据,或以各种方式对数据进行过滤(搜索索引(search indexes))向其他进程发送消息,进行异步处理(流处理(stream processing))定期处理累积的大批量数据(批处理(batch processing))

可靠性:
故障(fault)
失败(failure)
故障通常定义为系统的一部分状态偏离其标准,而失效则是系统作为一个整体停止向用户提供服务。故障的概率不可能降到零,因此最好设计容错机制以防因故障而导致失效。本书中我们将介绍几种用不可靠的部件构建可靠系统的技术。

硬件故障
软件错误
人为错误

CH2#

关系模型

问题:与应用代码层的 OOP 不匹配,需要 ORM

SQL

文档模型
天然 OOP。
但是对于多对多关系不好处理。
在需要连接的情况下,可能得需要应用层手动连接

图数据模型

Cypher 查询语言

RDF 数据模型

存储引擎
日志式
页面式

以日志式的 KV 为例

  1. 通过索引快速定位数据
  2. 执行压缩和分段合并(所以如何避免最终用完磁盘空间?一种好的解决方案是,将日志分为特定大小的段,当日志增长到特定尺寸时关闭当前段文件,并开始写入一个新的段文件。然后,我们就可以对这些段进行压缩(compaction))

Hash Index

SSTable (对于不存在的键,性能低下,存储引擎通常使用额外的 Bloom 过滤器)

B 树索引

基于 page
问题:在更新时,更新一个页面可能会导致页面拆分,这导致除了写两个新页外,还需要修改父页面的引用。这个过程并非是原子性的。
这导致崩溃时,整个存储不一致,因此需要 WAL,来做一个 redo log
在对外的并发时,多个线程看到的页面不一致,需要做特殊处理

优化:
写时复制(CopyOnWrite):修改的页面被写入到不同的位置,并且树中的父页面的新版本被创建,指向新的位置。

数据模型与查询方式#
数据存储与索引#

数据 Schema 格式及其演化#

数据序列化、反序列化(编码格式)#

文本、人类可读、二进制
Self Contained 如 JSON,XML,CSV
Schema First 如 Thrift、Proto Buffer、Avro

数据类型

  1. 如何编解码
  2. 格式的可读性、空间效率
  3. Schema 的变动处理
向前、向后兼容性#

面对变化的处理、向前、向后兼容性
向前:用新 Schema 去解释以前的值,(对于服务端而言,旧客户端会提供旧的值)
向后:用旧 Schema 去解释新增的值,(对于客户端而言,服务端会提供新的值)

此外,同一时刻,系统内部可能存在多个不同 Schema 版本,有的是 5 年前写入的,有的是一年前写入的。

数据的流动模式#
数据库中的数据流动#
服务中的数据流动#
REST/RPC#

REST 提倡:

  • 使用 URL 来标识资源
  • 使用 HTTP 功能进行缓存控制
  • 使用 HTTP 身份验证和内容类型协商
  • 采用 OpenAPI 描述 API,人类可读

SOAP :

  • 应当传输层无关(通常使用 HTTP,但不一定需要 HTTP)
  • 数据格式通常为 XML
  • 通过 WSDL 进行 API 描述
  • 并且内置了一系列,WS-* 的标准来实现诸如缓存、身份验证的业务需求

RPC 相比于本地的函数调用,十分不可靠,需要更多的手段来保障其可靠性。比如延迟高,网络失败(请求丢失,响应丢失),因此为了保障恰好执行一次,需要做好错误处理、幂等、重试等保障机制。

也就是需要明确的是,RPC,不是本地函数调用,非常不同,因此需要完全不同的处理手段。
通常会使用 Future / Promise 这样的手段进行封装。
部分框架还提供服务发现机制。

服务定义与服务实现的编写的耦合度

RPC 演化#

一个系统有多个 RPC 服务,现实的需求必然是每个 RPC 的 Schema 能够独立更改。而且更新的模式期望是:先更新 RPC 服务端,后更新 RPC 客户端。
因此,可以简化兼容需求:只需要在请求上向后兼容,在响应上向前兼容。

服务兼容性变得更加困难,因为 RPC 通常用于跨组织边界的通信,因此服务提供者通常无法控制其客户端,也无法强制它们升级。因此,兼容性需要保持很长时间,也许是无限期的。如果需要破坏兼容性的更改,服务提供者通常最终会并行维护服务 API 的多个版本。

持久执行和工作流#
事件驱动数据流#

多服务工作流协调
持久化执行
基于 MQ 的 EventDriven 架构/ 消息代理

  • 如果接收者不可用或过载,MQ 可以充当缓冲区,从而提高系统可靠性。
  • MQ 可以自动将消息重新传递给已崩溃的进程,从而防止消息丢失。
  • MQ 避免了服务发现的需要,因为发送者不需要直接连接到接收者的 IP 地址。
  • MQ 允许将相同的消息发送给多个接收者。
  • MQ 在逻辑上将发送者与接收者解耦(发送者只是发布消息,不关心谁使用它们)。

Actor 模式