分布式系统中只有两个难题(上)

简介: 分布式系统中只有两个难题(上)

3 分布式系统抽象

讨论编程语言时,我们使用通用术语并用函数、运算符、类、变量和指针来定义我们的程序。通用的词汇可以帮助我们避免每次都为了描述某些东西而发明新词。我们的定义越精确、越没有歧异,听众也就越容易理解。

在开始学习算法之前,我们首先要了解分布式系统中的词汇:这些定义你会经常在演讲、书籍和论文中遇到。


链路

网络是不可靠的:消息会丢失、延迟或被打乱。记住这一点之后,我们来尝试构建几种通信协议。我们从最不可靠的协议开始,确定它们可能处于的状态,然后找出可以为协议增加的东西使它提供更好的保证。


公平损失链路

我们可以从两个进程开始,它们之间以链路相连。进程可以相互发送消息,如图2所示。任何通信介质都是不完美的,消息可能丢失或延迟。

看看我们能得到什么样的保证。消息M被发送之后(从发送方的角度来看),它可能处于以下状态之一:

  • 还未送达进程B(但会在某个时间点送达)
  • 在途中丢失且不可恢复
  • 成功送达远程进程


image.png


注意,发送方没有任何方法确定消息是否已经送达。在分布式系统的术语中,这种链路称为公平损失(fair-loss)。这种链路具有以下属性:


公平损失

       如果发送方和接收方都是正确的,且发送方无限多次重复发送,则消息最终会被送达注3。

有限重复

       发送的消息不会被送达无限次。

不会无中生有

       链路不会自己生成消息。换句话说,它不会传递一个从未发送过的消息。


公平损失链路是一种很有用的抽象,它是构建具有更强保证的通信协议的基石。我们可以假设该链路不会在通信双方之间系统性地丢弃消息,也不会创建新消息。但与此同时,我们也不能完全依靠它。这可能让你想起了用户数据报协议(UDP),UDP允许我们从一个进程发送消息到另一个进程,但在协议层面上不提供可靠的传输语义。


消息确认


为了改善这一情况、更清晰地获得消息状态,我们可以引入确认(acknowledgment)机制:接收方通知发送方消息已送达。为此,我们需要双向通信信道,并增加一些措施以区分不同的消息,例如序列号—单调递增的唯一消息标识符。


每个消息只要有唯一标识符就足够了。序列号只是唯一标识符的一种特殊情况,即使用计数器来获取标识符,从而实现唯一性。当使用哈希算法来唯一地标识消息时,我们应当考虑可能的冲突,并确保能消除歧义。


现在,进程A可以发送消息M(n),其中n是单调递增的消息计数器。B收到消息后立即向A发送确认ACK(n)。图8-3展示了这种通信形式。


image.png


确认消息,就像原始消息一样,也有可能在途中丢失。消息可能处于的状态数会稍有变化。在A收到确认之前,该消息仍处于我们前面提到的三种状态之一,但是,一旦A收到确认,就可以确信该消息已送达B。


消息重传



增加确认机制仍不足以保证通信协议完全可靠:发送的消息仍可能会丢失,远程进程也可能在确认之前发生故障。为了解决该问题并提供送达保证,我们可以尝试重传(retransmit)。重传是指发送方重试可能失败的操作。我们之所以说可能失败,是因为发送方并不能真的知道有没有失败,因为我们要讨论的链路不使用确认机制。


进程A发送消息M之后,它将等到超时T被触发,然后尝试再次发送同一条消息。假设进程之间的链路完好无损,进程间的网络分区不会无限持续下去,并且并非所有数据包都丢失,我们可以认为,从发送方的角度看,消息要么尚未送达进程B,要么已经成功送达。由于A一直在尝试发送消息,可以认为传输过程中不会发生不可恢复的消息丢失。




在分布式系统的术语中,这种抽象称为顽固链路(stubborn link)。之所以称为顽固,是因为发件人会无限期地反复发送消息,但是,由于这种抽象非常不切实际,因此我们需要将重试与确认结合起来。


重传的问题

每当我们发送消息时,在收到远程进程的确认之前,我们无从得知消息的状态:可能已被处理,可能马上就要处理,也可能已经丢失,甚至可能在收到消息之前远程进程就崩溃了—上述的任意状态都是可能的。我们可以重试操作、再次发送消息,但这可能导致消息重复。只有当我们要执行的操作是幂等时,处理重复消息才是安全的。


幂等(idempotent)的操作可以执行多次而产生相同的结果,且不会产生其他副作用。例如,服务器关机操作可以是幂等的,第一次调用将发起关机,而所有后续调用都不会产生任何其他影响。


如果每个操作都是幂等的,那我们可以少考虑一些传递语义,更多地依赖重传来实现容错,并以完全反应式的方式构建系统:为某些信号触发相应的操作,而不会引起预期之外的副作用。但是,操作不一定是幂等的,简单地假设它们幂等可能会导致集群范围的副作用。例如,向客户的信用卡收费不是幂等操作,绝对不可以重复收费多次。


在存在部分故障和网络分区的情况下,幂等性尤其重要,因为我们无法总是确定远程操作的确切状态—是成功还是失败,还是会马上被执行—我们只能等待更长的时间。保证每个操作都是幂等的是不切实际的,因此我们需要在不改变实际操作语义的情况下,提供与幂等性等价的保证。为此,我们可以使用去重来避免多次处理消息。



相关文章
|
缓存 负载均衡 算法
“软件系统三高问题”高并发、高性能、高可用系统设计经验
​ 总的来说解决三高问题核心就是 “分字诀” 业务分层、系统分级、服务分布、数据库分库/表、动静分离、同步拆分成异步、单线程分解成多线程、原数据缓存分离、分流等等。。。。 直观的表述就是:从前端用的CDN、动静分离,到后台服务拆分成微服务、分布式、负载均衡、缓存、池化、多线程、IO、分库表、搜索引擎等等。都是强调一个“分”字。
1508 0
“软件系统三高问题”高并发、高性能、高可用系统设计经验
|
5天前
|
消息中间件 大数据 分布式数据库
分布式事务:构建可靠分布式系统的基石
【4月更文挑战第21天】分布式事务是确保现代分布式系统数据一致性和完整性的关键技术,涉及多服务协调,面临网络延迟、故障和数据一致性等问题。本文探讨了分布式事务的原理,包括两阶段提交、三阶段提交、分布式锁和补偿机制等解决方案,并阐述其在微服务、分布式数据库和消息队列等场景的应用。面对挑战,我们需要持续优化分布式事务处理机制。
|
9月前
|
消息中间件 人工智能 缓存
业务实现真的会因为分布式系统而变得简单么?
在当前互联网技术不断发展的时代,分布式系统成为了许多企业业务中不可或缺的一部分。分布式的出现,一方面提高了系统的可靠性和性能,另一方面也提高了系统的可扩展性和灵活性,这也让分布式系统被广泛应用于各种业务场景中,例如电商、金融、物流等领域。再结合阅读了《聊一聊分布式系统中的时空观构建》这篇文章,更进一步了解分布式系统的空间观构建,通过生活中的时间观念、事情的因果顺序、逻辑时钟等方面让业务实际因为分布式系统变得简化,而更易实现。但是实际的业务实现真的会因为分布式系统而变得更简单么?本文就来简单的聊一下。
52 1
业务实现真的会因为分布式系统而变得简单么?
|
10月前
|
消息中间件 canal 缓存
消息架构的设计难题以及应对之道
消息架构的设计难题以及应对之道
58 1
|
11月前
|
负载均衡 Kubernetes 算法
【韧性架构设计】分布式系统的韧性
【韧性架构设计】分布式系统的韧性
|
11月前
|
运维 安全 中间件
【分部式架构】分布式系统的挑战
【分部式架构】分布式系统的挑战
|
存储 缓存 cobar
分布式系统设计实践
分布式系统设计实践
220 0
|
运维 算法 网络协议
分布式系统中只有两个难题(下)
分布式系统中只有两个难题(下)
258 0
分布式系统中只有两个难题(下)
|
运维 算法 NoSQL
关于分布式系统共识的思考
在前面的文章里,我们分析了分布式系统在业务上的一致性技术,即分布式事务,它的结果导向是面向用户的。然而在我们的系统内部,有时也需要面对来自软件架构等更高层次上的一致性要求,比如 Redis 的哨兵模式,Zookeeper 的选举过程等。它们所考虑的一致性更多的是服务节点之间一个共识的达成,当共识达成之后,就可以以此为指导原则,展开更多的协同操作
217 0
关于分布式系统共识的思考
|
存储 并行计算 负载均衡
反常理,反直觉,区块链是怎样的一种“分布式系统”
我们经常看到“区块链是分布式系统”的说法,并推论出区块链先天具备分布式系统的优势,仿佛作为分布式系统,规模就该足够大,数据就该足够分散。 事实上,典型区块链有很多特征和常见的分布式系统不同,甚至是相悖的,为此,区块链曾被戏称为“最慢的分布式数据库”。 其实区块链之所以难以理解,其中一个原因是其设计哲学的“反常理、反直觉”。笔者本人曾多年在互联网海量服务领域里踩坑,然后转向区块链领域深入研究,也经历过一阵子的观念切换期。 本文不打算全面讲述分布式系统原理和历史,那能写几本书。这里打算从常见的、被人广泛认知的互联网分布式系统出发,聊聊“分布式系统”和区块链有什么异同,对技术和设计的要求有哪些
168 0