分布式系统关键概念和模式 - klarna


如果您在一家现代科技公司工作,您可能遇到过“分布式系统”一词。在这篇博文中,我将分两部分进行介绍,第一部分是关于关键概念和时间表,第二部分是关于行业中使用的一些模式。这篇博文的目的是分享足够的基础信息和资源,如果有兴趣,您可以自行深入挖掘。

两位将军的问题 — 1975
两名陆军将军正试图协调进攻。他们应该决定一个时间,双方一起进攻,只有他们一起进攻,他们才能获胜。他们之间的道路被反对派军队掩护。一位将军派遣一名士兵告知他要进攻的时间,另一位将军应回复“确定”。问题是,

  • 如果士兵在到达另一边之前死在中间怎么办?或者
  • 如果士兵在回来的路上死了怎么办?

由于不可靠的通信渠道,这个问题被证明是不可能解决的。这个问题解释了为什么 TCP 不能保证其端点之间的状态一致性。相反,为了长时间等待确认,我们使用超时并重试方法。这个术语在 1975 年左右首次被提及。它也经常与Byzantine Fault一起讨论。

两阶段提交 (2PC) — 1985
2 Phase Commit 是分布式数据库中最早的解决方案之一,但由于其缺点,它从未得到足够的普及。在多节点数据库中,一个节点充当协调者,其他节点充当参与者。交易分两个阶段进行(因此名称),

  • 准备阶段:询问每个节点是否能够承诺执行更新
  • 提交阶段:实际执行。

显着的缺点是
  • 如果协调器在第一阶段后死亡,它可以进入阻塞状态
  • 很慢

共识与 Paxos — 1989
“Paxos 保证,如果一个同行认为某些价值已被大多数人同意,那么大多数人永远不会同意不同的价值。”

Paxos 作为共识协议是分布式系统向前迈出的一大步。简而言之,Paxos 在 2PC 中转向了法定人数多数方法与来自所有节点的协议。Paxos 或其变体 (Raft) 仍在现代分布式系统中使用,例如 Chubby、Zookeeper、Consul 等。这是Raft 协议的一个非常好的可视化表示。

有趣的事实:发表 Paxos的原始论文非常复杂,以至于每个人都无法理解 Leslie Lamport在 2001 年发表了一篇新论文 Paxos Made Simple

CAP 定理 — 2000
CAP 定理解释了分布式系统的三个主要组成部分。它指出,
“在分布式系统中,当存在网络分区时,您只能拥有两种保证之一,即一致性或可用性。”

人们经常被误导,认为它是从 3 中选择任意 2 个。这是不正确的,因为网络分区总是会在分布式系统中发生。因此,我们要么必须选择一致性,要么必须选择可用性。


Spanner — 2012
Spanner 是 Google 开发的分布式 SQL 数据库管理和存储服务,于 2012 年推出。Google 声称 Spanner 是 CA(Consistent and Available)系统,从而击败了 CAP 定理。

有趣的是,谷歌的声明是基于谷歌使用自己的网络基础设施的条款。因此,将网络分区最小化到几乎为零。如果谷歌使用普遍可用的公共网络,这是不可能的。

谷歌的受控网络使其能够使用其 TrueTime API 实现时钟同步和全球一致性。

恰好一次交付
Exactly Once Delivery 是指如果一条消息从一个系统发送到另一个系统,它会恰好到达另一个系统一次,不多不少。

Martin Kleppmann 在他的“设计数据密集型应用程序”一书中写道,这个术语应该改写为Effectively Once Processing。

如果发送消息的系统在收到 ACK 之前出现故障,它将再次产生相同的消息。为了解决这个问题,中间的broker需要去重。此外,如果消息的消费者(接收者)在为其收到的消息发送 ACK 之前死亡,它将再次收到相同的消息。这意味着它需要是幂等的。当您查看整个系统时,消费者可能会不止一次收到相同的消息,但它会确保只处理一次并且以后收到的消息不会产生副作用。

分布式系统只有两个难题:

  1. 保证消息的顺序
  2. 精确一次交付

事件溯源
在事件溯源中,不可变事件存储在仅附加的持久存储中。事件存储可以将原始事件推送到服务,或者服务可以通过调用存储来获取最新状态。系统最终是一致的,要求消费者是幂等的。

优点

  • 事件是不可变的
  • 事件存储是仅附加日志
  • 事件存储提供审计线索
  • 随时重新播放以获得最新状态

缺点
  • 事件粒度永远不明确
  • 架构更新很难(需要版本控制)
  • 不,撤消/更新
  • 需要快照
  • 需要清楚地了解业务领域

例子

  • 版本控制系统

Chris Richardson 写了一篇关于事件溯源的非常好的文章。您还可以阅读Martin Fowler 的著作


CQRS
命令和查询责任分离 (CQRS) 是一种分离数据存储的读取(查询)和更新(命令)操作的模式。它与分布式系统没有直接关系,但通常与基于事件的系统一起使用,例如事件溯源。

对于上面的示例,CQRS 模型如下图所示。来自持久存储的事件将以特定格式发布到另一个存储(数据库)。表示层可以根据需要查询数据库。

优点

  • 非常适合基于事件的系统。
  • 性能优势。分离命令和查询之间的负载。
  • 模型可以完全相互隔离。

缺点
  • 拥有两个独立的模型需要逻辑来保持它们的一致性。大多数情况下它最终是一致的。
  • Query 模型将具有与 Command 模型不同的模式。
  • CQRS 的基本思想很简单。但它会导致更复杂的应用程序设计,尤其是当它们包含事件溯源模式时。

这是Martin Fowler对 CQRS 的一个很好的解释。

Saga
Saga 设计模式是一种在分布式事务场景中跨微服务管理数据一致性的方法。saga 是一系列事务,它更新每个服务并发布消息或事件以触发下一个事务步骤。如果一个步骤失败,saga 会执行抵消前面事务的补偿事务。

Orchestration 是一种协调 sagas 的方法,其中一个集中控制器告诉 saga 参与者要执行哪些本地事务。saga orchestrator 处理所有事务并根据事件告诉参与者执行哪个操作。

优点

  • 适用于涉及许多参与者或随着时间推移添加的新参与者的复杂工作流程。
  • 参与者松散耦合
  • 可以处理长时间运行的事务

缺点
  • 服务需要有补偿事务
  • 额外的设计复杂性
  • 这可能会导致服务之间的循环依赖
  • 对于复杂的流程,端到端测试可能很棘手
  • 这可能导致 Dumb Services、Smart Orchestrator

Microsoft Azure Architectures对 SAGA有详细的解释。


CDC/发件箱
更改数据捕获 (CDC) 和发件箱模式非常相似。主要概念是事件源自数据库的内部日志(即 WAL)。执行操作时,服务只需提交数据库中的更改,无需担心在事务中发布事件。数据库充当真相的来源。

优点

  • 易于在现有系统中实施
  • 独立 CDC 连接器

缺点
  • 触发器开销(为每个表定义)
  • 仅适用于基于日志的数据库
  • 没有可靠的开源工具
  • 需要维护数据库日志和事件之间的模式映射