仅一个进程故障就无法达成共识
仅一个进程故障指的是在异步的分布式系统中
异步系统的共识问题(consensus)涉及一组进程,其中有的进程可能不可靠(unreliable)。共识问题要求可靠的进程一致地从两个侯选中决定(agree)一个。本文表明解决该问题的任何协议都可能不终止,即使故障(faulty)进程只有一个。相比而言,同步系统的共识问题,即“拜占庭将军”问题,已有解决方案。
一、简介
在分布式计算中,达成远程进程之间的一致性是最基本的问题之一,并且是许多分布式数据处理、分布式文件管理和容错分布式应用程序算法的核心。
远程进程之间达成一致的问题是分布式计算中最基本的问题之一,也是许多分布式数据处理算法、分布式文件管理和容错分布式应用程序的核心问题。一个众所周知的问题形式是“事务提交问题”,它在分布式数据库系统中出现[6, 13, 15-17, 21-24](参见G. LeLann的私人通信,在[15]中引用)。问题是,所有参与处理特定事务的数据管理进程必须就是是否将事务的结果安装到数据库中或者丢弃它们达成一致的决定。如果由于某种原因一些数据管理进程无法执行所需的事务处理,可能需要执行后者操作。无论做出什么决定,所有数据管理者必须做出相同的决定,以保持数据库的一致性。
共识问题的定义。
共识问题的例子:事务提交问题
实现“commit”问题所需的类型的协议对于参与进程和网络完全可靠的情况来说是很简单的。然而,真实的系统会遭受多种可能的故障,如进程崩溃、网络分区以及丢失、失真或重复的消息。甚至可以考虑更多的拜占庭式的失败[5,7,8,11,14,18,19],在这种情况下,有缺陷的进程可能会完全失控,甚至按照某种恶意计划发送消息。因此,我们希望在面对这些故障时,拥有尽可能可靠的协议。当然,任何协议都可能被太频繁或太严重的故障压垮,所以我们所期望的是一个能够容忍一定数量“预期”故障的协议。
希望能够容忍一定数量的失败
在这篇论文中,我们展示了一个令人惊讶的结果,**即没有任何完全异步的共识协议能够容忍即使一个未经通知的进程死亡的情况。**我们不考虑拜占庭故障,并且我们假设消息系统是可靠的,它可以正确地且仅一次地传递所有消息。然而,即使在这些假设下,一个进程在不适宜的时间停止运行可以导致任何分布式共识协议无法达成一致。因此,这个重要问题在没有进一步关于计算环境的假设或对可容忍故障类型的更大限制的情况下没有健壮的解决方案!
即使不考虑拜占庭失败以及假设消息系统是可靠的,在这两个前提下,仍旧不能达到一致
我们证明的关键是处理是完全异步进行的;也就是说,我们对处理器的相对速度或传递消息的延迟时间没有任何假设。我们还假设进程无法使用同步时钟,因此不能使用基于超时的算法。 (特别地,在[6]中的解决方案不适用。)最后,我们不假设可以检测到进程的死亡,因此一个进程无法确定另一个进程是否已经死亡(完全停止)或者仅仅运行得很慢。
异步的定义:对处理器的相对处理速度或者传递消息的延迟没有任何的假设。
假设没有时钟,没有超时机制。
假设不能检测进程的死亡。
我们的不可能性结果适用于共识问题的一个非常弱的形式。假设每个进程都从区间(0, 1)内的一个初始值开始。非故障进程通过进入适当的决策状态来决定一个区间(0, 1)内的值。所有非故障进程在做出决策时都被要求选择相同的值。为了证明不可能性,我们只需要最终某个进程做出决策。(当然,任何有兴趣的算法都需要所有非故障进程做出决策。)对应于不同的初始配置,我们规定 0 和 1 都是可能的决定值;这就排除了类似“总是选择 0”的简单方案。
不可能性在非常弱的场景下都是成立的,那么在更复杂的现实情况下不可能性成立更是显然的。
此外,论文只要求了某个正常的进程做出决策,并没有要求所有的非故障进程都做出决策。一般的论文都是要求所有的非故障进程都要做出正确决策。
如果某个正常的进程都不能做出决策,那么也就是结论:没有进程能够做出正确决策。——这是一个更强的否定。
我们的系统模型非常强大,以尽可能广泛地适用于我们的不可能性证明。进程被建模为自动机(可能有无限多个状态),通过消息进行通信。在一个原子步骤中,进程可以尝试接收消息,在基于消息是否被传递给它以及传递的消息是哪一个的基础上进行局部计算,并将任意但有限数量的消息发送给其他进程。特别地,假设具有“原子多播”能力,以便一个进程可以在一步中将相同的消息发送给所有其他进程,并且知道如果有任何非故障进程接收到该消息,则所有非故障进程都会接收到。只要目标进程进行无限次尝试接收,每条消息最终都会被传递,但是消息可能会被延迟任意长时间,并且可能按照任意顺序进行传递。
问题模型:进程是传递消息的自动机,通过消息进行通信。
消息收发—> 状态集计算----->消息收发
当前使用的异步提交协议似乎都存在“漏洞窗口”,即在算法执行期间的一段时间内,单个进程的延迟或不可访问性可能导致整个算法无限等待。根据我们的不可能性结论,每个提交协议都有这样的“窗口”,证实了民间智慧中广泛认为的原理。
证明了漏洞窗口的存在
二、共识协议
一致性协议P是一个具有N个进程(N大于等于2)的异步系统。每个进程p都有一个一位输入寄存器 x p x_p xp,一个取值为(b, 0, 1)的输出寄存器 y p y_p yp,以及无限量的内部存储空间。输入和输出寄存器的取值,加上程序计数器和内部存储,构成了内部状态。初始状态规定了除了输入寄存器之外的所有起始值;特别地,输出寄存器的初始值为b。**输出寄存器取值为0或1的状态被认为是决策状态。**进程p根据一个过渡函数进行确定性操作。一旦进程到达决策状态,过渡函数就不能改变输出寄存器的值;也就是说,输出寄存器是“只写”的。整个系统P由与每个进程对应的过渡函数和输入寄存器的初始值来规定。
基本模型:
- 进程建模:系统由数量N>2的进程构成。进程被建模为状态机,进行的动作即为由消息驱动的计算,通过对消息的收发进行的计算推动状态机的状态变化。每个进程具有一定的内部状态。内部状态包括输入、输出寄存器的取值,和程序计数器以及内部存储值。进程还有
输入寄存器:收消息的buffer
输出寄存器:输出最后的结果
内部状态:输入、输出和寄存器的取值、程序计数器和内部存储
- 初始状态:规定了除了输入寄存器外的所有值
- 输出寄存器:b。当其取值为0或者1时的状态被认为是决策状态。
- 过渡函数:执行确定性操作。
进程通过发送消息来进行通信。消息是一个二元组 ( p , m ) (p, m) (p,m),其中p是目标进程的名称,m是来自固定宇宙M的“消息值”。消息系统维护一个多重集合,称为消息缓冲区,其中包含已发送但尚未传递的消息。它支持两种抽象操作:
send(p,m)
:把消息 ( p , m ) (p,m) (p,m)放到消息缓冲区receive(p)
:从缓冲区删除消息 ( p , m ) (p,m) (p,m)并且返回 m m m。在这种情况下,我们说 ( p , m ) (p,m) (p,m)被传送(delivered),或者返回特殊的空值并保持缓冲区不变
因此,消息系统以非确定性方式运作,只有一个条件:如果receive(p)
无限次执行,则消息缓冲区中的每个消息 ( p , m ) (p, m) (p,m)最终都会被传递。特别是,尽管缓冲区中存在消息 ( p , m ) (p, m) (p,m),消息系统仍可以有限次地返回0作为对receive(p)
的响应。
系统的配置(configuration)由每个进程的内部状态以及消息缓冲区的内容组成。初始配置是指每个进程都处于初始状态,并且消息缓冲区为空。
配置 1 − − − 收发消息与计算(步骤) − − − > 配置 2 配置1---收发消息与计算(步骤)--->配置2 配置1−−−收发消息与计算(步骤)−−−>配置2
注意,系统的配置指的是系统中所有的进程的内部状态以及消息缓冲区。与进程自身的自动机是不同的两个概念。
一个步骤(step)将一个配置转换到另一个配置,且仅由单个进程 p p p的基本步骤组成。记 C C C为一个配置。一个步骤分两阶段执行。首先,在 C C C的消息缓冲区上执行 receive ( p ) \text{receive}(p) receive(p),获取值 m ∈ M ∪ ∅ m \in M \cup {\emptyset} m∈M∪∅。之后,取决于 C C C中进程 p p p的内部状态和消息 m m m, p p p转换到新的内部状态,并向其它进程发送有限数量的一组消息。由于进程是确定性的,因此该步骤完全取决于消息 e = ( p , m ) e=(p, m) e=(p,m),我们称之为事件(event,此“事件”应认为是“ p p p收到 m m m”)。 e ( C ) e(C) e(C)表示产生的新配置,我们说 e e e可以应用到 C C C。注意事件 ( p , ∅ ) (p, \emptyset) (p,∅)总是可以应用于 C C C,所以进程总是可以执行一个步骤。
步骤的概念
步骤包括两个基本步骤:
receive(p)
的执行,获取消息- 根据消息和内部状态转换到新的内部状态,并向其他进程发送数量有限的一组消息
事件的定义:事件e由消息(p, m)即来自某个进程的消息m,目标进程是p
从 C C C开始的一个调度(schedule),是一个有限或无限的事件序列 σ \sigma σ,它们从 C C C开始,依次应用。相关的步骤序列称为一次执行(run)。若 σ \sigma σ是有限的,我们令 σ ( C ) \sigma(C) σ(C)表示产生的新配置,称它可以从 C C C到达(reachable)。从某个初始配置可到达的配置称为可达的(accessible)。下文涉及的所有配置都假设是可达的。
调度的概念:
- 调度是若干事件的序列(事件是作用于p的消息)
执行的概念:
- 步骤序列称为一次执行
可达:
- 从某个初始配置可到达的配置称为可达的
以下引理表明调度的“交换性”(commutativity)。
引理 1:假设从某配置 C C C开始,调度 σ 1 \sigma_1 σ1, σ 2 \sigma_2 σ2,分别产生配置 C 1 C_1 C1, C 2 C_2 C2。如果 σ 1 \sigma_1 σ1与 σ 2 \sigma_2 σ2中的进程集彼此不相交,那么 σ 2 \sigma_2 σ2可以应用于 C 1 C_1 C1,且 σ 1 \sigma_1 σ1可以应用于 C 2 C_2 C2,并且都产生相同的配置 C 3 C_3 C3(见图 1)。
证明:因为 σ 1 \sigma_1 σ1与 σ 2 \sigma_2 σ2没有关联,由系统定义可以直接得出结论。
如果某个进程 p p p处于决定状态,且 y p = v y_p=v yp=v,那么我们说该配置 C C C的决定值为 v v v。若共识协议满足下面两个条件,则它是部分正确的(partially correct):
- 所有可达配置的决定值不超过一个。
- 某个可达配置的决定值为 v v v,且 v ∈ { 0 , 1 } v \in \set{0, 1} v∈{0,1}。
若在某次执行中,进程 p p p可以执行任意多的步骤,就称为无故障的(non-faulty),否则是有故障的(faulty)。如果至多有一个进程有故障,且发送给无故障进程的消息最终都被收到,那么称这一执行是可接受的(admissible)。
系统有无故障的定义
系统可接受的定义
若某个进程在执行中达到决定状态,就称此次执行是有决定的(deciding)。如果共识协议 P P P是部分正确的,且每个可接受的执行都是有决定的,那么称其在一个进程故障的情况下仍完全正确(totally correct in spite of one fault)。我们的主定理表明,共识问题的所有部分正确协议都存在可接受但没有决定的执行。
有决定的:进程在执行中达到决定状态
完全正确:共识协议P是部分正确的,且每个可接受的执行都是有决定的。
三、主要结论
定理1:没有共识协议在一个进程故障情况下仍完全正确(No consensus protocol is totally correct in spite of one fault)。
反证。假设共识协议 P P P在一个进程故障的情况下仍完全正确。我们来证明一系列引理,最终导致矛盾。
基本想法是展示协议永远无法决断的情况。这包括两个步骤。首先,我们表明存在某个初始配置,不能预先确定决定值。其次,我们构造一个可接受的执行,总是避免系统执行做出决定的步骤。
令 C C C为一个配置, V V V是从 C C C可到达配置的决定值的集合。若 ∣ V ∣ = 2 |V|=2 ∣V∣=2,称 C C C是双值的(bivalent)。若 ∣ V ∣ = 1 |V|=1 ∣V∣=1,称 C C C是单值的(univalent),根据相应的决定值,分别称为“值-0”(0-valent)或“值-1”(1-valent)。由于 P P P是完全正确的,以及总有可接受的执行的事实, V ≠ ∅ V \ne \emptyset V=∅ 译注:从而 ∣ V ∣ ≠ 0 |V| \ne 0 ∣V∣=0。
引理 2: P P P存在双值的初始配置。
证明:假设不存在。因为假设 P P P是部分正确的,所以 P P P必定同时具有“值-0”和“值-1”的初始配置译注:这两类初始配置都是单值的。对两个初始配置,如果它们仅有一个进程 p p p的初始值 x p x_p xp不同,那么称这两个配置是毗连的(adjacent)。任意两个初始配置都可以通过一系列毗连的初始配置联系起来。因此,必然存在一个“值-0”的初始配置 C 0 C_0 C0与一个“值-1”的初始配置 C 1 C_1 C1毗连。令 p p p为它们之中初始值不同的那个进程。
现在考虑从 C 0 C_0 C0开始的某个可接受且有决定的执行,其中进程 p p p不执行任何步骤,令 σ \sigma σ是该执行的调度。那么 σ \sigma σ也可以应用于 C 1 C_1 C1,而且除了进程 p p p的内部状态外,两次执行对应的配置是相同的。易见,两次执行最终会决定相同的值。若决定的值为1,则 C 0 C_0 C0是双值的;否则, C 1 C_1 C1是双值的。这两种情况都与假定不存在双值的初始配置相矛盾。
引理 3:令 C C C是 P P P中一个双值配置, e = ( p , m ) e=(p,m) e=(p,m)是一个可应用于 C C C的事件。令 C \mathscr{C} C是从 C C C无需应用 e e e即可到达配置的集合, D = e ( C ) = { e ( E ) ∣ E ∈ C \mathscr{D} = e(\mathscr{C}) = \{e(E) | E \in \mathscr{C} D=e(C)={e(E)∣E∈C 且 e e e可以应用于 C } \mathscr{C}\} C}。那么, D \mathscr{D} D包含双值的配置。
证明:既然 e e e可以应用于 C C C,那么由 C \mathscr{C} C的定义,及消息可以任意延迟的事实, e e e可以应用于每个 E ∈ C E \in \mathscr{C} E∈C。
假设 D \mathscr{D} D不包含双值配置,那么其中的每个配置 D ∈ D D \in \mathscr{D} D∈D都是单值的。我们来推导出矛盾。
令 E i E_i Ei是“值- i i i”的配置,可以从 C C C到达, i = 0 , 1 i=0, 1 i=0,1(因为 C C C是双值的,故 E i E_i Ei存在)。若 E i ∈ C E_i \in \mathscr{C} Ei∈C,令 F i = e ( E i ) ∈ D F_i = e(E_i) \in \mathscr{D} Fi=e(Ei)∈D。否则,在到达 E i E_i Ei的执行中就应用过了 e e e,故存在 F i ∈ D F_i \in \mathscr{D} Fi∈D,且从 F i F_i Fi可到达 E i E_i Ei。在任一情况下, F i F_i Fi都是“值- i i i”的,由于 F i F_i Fi不是双值的(因为 F i ∈ D F_i \in \mathscr{D} Fi∈D,而 D \mathscr{D} D不包含双值配置)且 E i E_i Ei可到达 F i F_i Fi或反之。由于 F i ∈ D F_i \in \mathscr{D} Fi∈D, i = 0 , 1 i = 0, 1 i=0,1, D \mathscr{D} D同时包含“值-0”和“值-1”的配置。
若一个配置经一步到达另一个配置,则称这两个配置是邻居(neighbors)。通过简单的归纳,存在邻居 C 0 , C 1 ∈ C C_0,\ C_1 \in \mathscr{C} C0, C1∈C,且 D i = e ( C i ) D_i = e(C_i) Di=e(Ci)是“值- i i i”的, i = 0 , 1 i = 0, 1 i=0,1。不失一般性,令 C 1 = e ′ ( C 0 ) C_1 = e'(C_0) C1=e′(C0),其中 e ′ = ( p ′ , m ′ ) e'=(p',m') e′=(p′,m′)。
情况1:若 p ′ ≠ p p' \ne p p′=p,由引理1,得 D 1 = e ′ ( D 0 ) D_1 = e'(D_0) D1=e′(D0)。这是不可能的,因为“值-0”配置的任何后继都是“值-0”的(见图 2)。
情况2:若 p ′ = p p' = p p′=p,考虑从 C 0 C_0 C0的任意有限步有决定的执行,其中 p p p不执行任何步骤。
令 σ \sigma σ是相应的调度, A = σ ( C 0 ) A = \sigma(C_0) A=σ(C0)。由引理 1, σ \sigma σ可应用于 D i D_i Di,并产生“值- i i i”的配置 E i = σ ( D i ) E_i = \sigma(D_i) Ei=σ(Di), i = 0 , 1 i = 0, 1 i=0,1。同样由引理 1, e ( A ) = E 0 e(A) = E_0 e(A)=E0,且 e ( e ′ ( A ) ) = E 1 e(e'(A)) = E_1 e(e′(A))=E1(见图 3)。因此, A A A是双值的。但这是不可能的,因为到 A A A的执行是有决定的(由假设),所以 A A A必须是单值的。
在每种情况下,我们都遇到了矛盾,所以 D \mathscr{D} D包含双值的配置。