Lecture 04: VMware FT(MIT6.824)

这一节课更多地讨论一些关于容错(Fault-Tolerance)和复制(Replication)的问题以及VMware FT。容错本身是为了提供可用性,比如计算机硬件和网络都有可能出现问题,这里所使用的工具就是复制。那么复制到底能处理何种故障?

4.1 Failures​

Fail-stop faults

简单来说复制能够处理单台计算机的fail-stop故障,如果某些东西出现故障,只是单纯的停止运行,而不是运算出错误结果。 比如电源线、服务器风扇导致CPU过热停止运行、网络等故障。网络隔离场景很有趣,因为从外界来看,这和服务器停止运行毫无区别。

个人理解应该仅仅是停止运行,而不是运行产生错误的数据,进而对后面带来影响;不产生负面持久性的影响是关键。

Bugs

复制不能处理软件中的bug和硬件设计中的缺陷。 如果相同的程序,都计算出错误的结果,那么再多副本也都无法避免。我们也不能期望复制可以处理硬件的漏洞,当硬件有漏洞的时候会计算出错误的结果,至少基于复制这种技术,我们就无能为力了。
也有一些硬件和软件的bug是可以被复制处理掉的。比如kernel panic或者其它问题导致,对本服务来说也算是fail-stop,此时备份副本将会起作用。或者网络、磁盘等硬件错误,这些可以被checksum检查出来数据出错了,进而丢弃,或者通过纠删码修复等,这种都属于软件知道发成了错误,并可以将错误转换成一个fail-stop错误。

副本的独立性/关联性错误

我们总是假设两个副本的错误是独立的,如果有关联,那么复制就很难起到作用。比如从同一个厂商买了数千台完全一样的计算机,我们将我们的副本运行在这些同一时间,同一地点购买的计算机上,这还是有一点风险的。因为如果其中一台计算机有制造缺陷,那么极有可能其他的计算机也有相同的缺陷。还有就是数据中心所在地出现的停电等问题,也是很难避免的,一般希望能够物理上分开进而避免供电和自然灾害。

副本的代价权衡

这是一个经济上的问题,它取决于一个可用服务的价值。如果你在运行一个银行系统,并且计算机宕机的后果是你不能再为你的用户提供服务,你将不能再有任何收入,你的用户也会讨厌你,那么多花1000-2000美金再买一台计算机或许是值得的。这种情况下,你可以有一个额外的副本。但是另一方面,如果是这个课程的网站,我不认为它值得拥有一个热备份,因为这个课程网站宕机的后果非常小。对于系统做复制是否值得,该复制多少份,你愿意为复制花费多少,都取决于失败会给你带来多大的损失和不便。

4.2 状态转移和复制状态机(State Transfer and Replicated State Machine)

在VMware FT论文的开始,介绍了两种复制的方法:状态转移(State Transfer)复制状态机(Replicated State Machine)

State Transfer 状态转移

状态转移背后的思想是,Primary将自己完整状态,比如说内存中的内容,拷贝并发送给Backup。 Backup会保存收到的最近一次状态,当primary故障,backup可以从保存的状态开始运行。对于Vmware FT如果使用的话,就是内存里面的东西,Primary对自身的内存做一大份拷贝,或者采用增量方式只同步变更了的内存,最后通过网络完成传输。当然FT并未使用此方案。

Replicated State Machine 复制状态机

复制状态机基于:对于复制的服务 service 或者其它computer things,其内部操作都是确定的,除非有外部输入影响。例如同样的程序,同样的启动,那么运行的命令也都是确定执行的,当外部网络数据包等可能导致服务器状态发生改变。复制状态机不会发送内存状态,而是仅仅发送外部事件。对于primary-backup模型,仅将外部输入事件发送给backup副本。通常来说,如果有两台计算机,如果它们从相同的状态开始,并且它们以相同的顺序,在相同的时间,看到了相同的输入,那么它们会一直互为副本,并且一直保持一致。
状态转移传输的是可能是内存,而复制状态机会将来自客户端的操作或者其他外部事件,从Primary传输到Backup。通常外部操作或者事件比服务的状态要小,因此复制状态机通常来说更吸引人一些,但它更为复杂,需要对计算机的运行做更多的假设。状态转移就比较简单粗暴,只需要传递整个状态,但是代价非常大。

这里看到后面或者已经看过论文会更为了解。

学生提问:如果这里的方法出现了问题,导致Primary和Backup并不完全一样,会有什么问题?
Robert教授:GFS Master的Primary 和 Backup,主master对ChuckServer1发了租约,备master因为多副本不一致导致没有向任何人发出租约,它甚至都不知道任何人请求了租约。后面主master挂了,备master服务,之后将某些chunk的租约给了另外的ChunkServer,这时有两个有着相同的租约。这只是一个非常现实的例子,基于不同的副本不一致,你可以构造出任何坏的场景和任何服务器运算出错误结果的情形。我之后会介绍VMware的方案是如何避免这一点的。
学生提问:随机操作在复制状态机会怎么处理?
Robert教授:只有当没有外部的事件时,Primary和Backup都执行相同的指令,得到相同的结果,复制状态机才有意义。比如获取当前时间,或者计算随机数。Primary会执行这些指令,并将结果发送给Backup。Backup不会执行这些指令,而是在应该执行指令的地方,等着Primary告诉它,正确的答案是什么,并将监听到的答案返回给软件。
VMware FT论文讨论的都是复制状态机,并且只涉及了单核CPU,目前还不确定论文中的方案如何扩展到多核处理器的机器中。在多核的机器中,两个核交互处理指令的行为是不确定的,VMware在之后推出了一个新的可能完全不同的复制系统。教授认为使用了状态转移,因为面对多核和并行计算,状态转移更加健壮,不受并行计算的影响。

复制状态机需要考虑的问题

复制模型 (what we mean by state)

VM FT会复制机器的完整状态,包括了所有的内存,所有的寄存器,Primary和Backup即使在最底层也是完全一样的。大部分复制方案都跟GFS更像,采用应用程序级别的复制系统,复制这个行为,必须构建在应用程序内部。GFS复制的更多是应用程序级别的Chunk,通过将数据抽象成Chunk和Chunk ID,GFS只是复制了这些。对于应用程序来说,只要Chunk的副本数据一致即可。基本上所有的方案使用的都是应用程序级别的状态复制,因为这更加高效,并且更不会遇到需要确保中断在Primary和Backup的相同位置执行这种问题,但是VMware FT就需要担心这种情况,因为它从最底层就开始复制
VMware FT从机器级别实现复制,因此它不关心你在机器上运行什么样的软件,它就是复制底层的寄存器和内存。它的缺点是不够高效,优点是可以将任何现有软件(甚至无需知道源码),通过运行在VM FT上实现复制。

P/B Sync, P/B的同步频率

通常primary执行的较为超前,因此有可能primary出现故障,但是backup尚未完全同步;同样的保持P/B之间的完全同步执行就需要大量的交互/通信,代价非常高。因此在设计中都需要关注同步频率的设定。

异常时的P/B 切换方案 cur-over anomalies

如果Primary发生了故障,客户端都必须以某种方式切换到另一个副本。**几乎不可能设计一个不出现异常现象的切换系统。**在理想的环境中,如果Primary故障了,系统会切换到Backup,同时客户端并不会注意到这里的切换,但这在实际上基本不可能实现。在切换过程中必然会有异常,必须找到一种应对它们的方法。

新增backup副本 new replicas

创建一个新的副本,只能使用状态转移,因为新的副本需要有完整状态的拷贝,因此创建新副本代价会很高。

在讨论其他复制状态机方案时,会再次看到这些问题。

4.3 VMware FT 工作原理

技术前提:虚拟机通过在硬件上运行一个虚拟机监控器(VMM,Virtual Machine Monitor)或者Hypervisor,在同一个硬件上模拟出多个虚拟的计算机。通过VMM,可以在一个硬件上启动一到多个不同的操作系统的虚拟机。通过在硬件和操作系统之间的抽象,可以在每个操作系统里面运行一个小的服务,而不是购买大量的物理计算机,每个物理计算机只运行一个服务。
VMware FT需要两个物理服务器运行VMM,Primary虚机在其中一个物理服务器上,Backup在另一个物理服务器上,目标是让Primary和Backup的内存镜像完全一致;二者通过网络链接,同时还存在一些客户端通过网络向primary发送请求。在VMware FT里,多副本服务没有使用本地盘,而是使用了一些Disk Server(远程盘)。这里可以将远程盘服务器也看做是一个外部收发数据包的源,与客户端的区别不大。

客户端消息请求与响应

客户端的网络数据包产生一个中断,之后这个中断送到了VMM。VMM发现这是多副本服务的一个输入:一方面会模拟网络数据包到达的中断,以将相应的数据送给应用程序的Primary副本。除此之外,VMM会将网络数据包拷贝一份,并通过网络送给Backup虚机所在的VMM。最后Primary和Backup都有了这个网络数据包,它们有了相同的输入,再加上许多细节,它们将会以相同的方式处理这个输入,并保持同步。
Primary虚拟机里的服务的回复报文会通过VMM的模拟虚拟网卡发出,之后VMM将这个报文发送给客户端。Backup虚机运行了相同顺序的指令,同样会回复报文给客户端,通过它的VMM模拟出来的虚拟网卡发出,VMM知道这是Backup虚机,会丢弃这里的回复报文,最后只有primary的响应能够到达客户端。
VMware FT论文中将Primary到Backup之间同步的数据流的通道称之为Log Channel,从Primary发往Backup的事件被称为Log Channel上的Log Entry。
在这里插入图片描述

P/B 故障处理

当Primary因为故障停止运行时,FT(Fault-Tolerance)就开始工作了。从Backup的角度来说,它将不再收到来自于Log Channel上的Log条目。每个Primary的定时器中断都会生成一条Log条目并发送给Backup,这些定时器中断每秒大概会有100次。如果Primary虚机停止运行了,那么Backup的VMM超过一定时间之后,就会判断Primary一定是挂了或者出什么问题了。Backup虚机会上线(Go Alive),Backup不会再等待来自于Primary的Log Channel的事件,Backup的VMM会让Backup自由执行,而不是受来自于Primary的事件驱动。Backup的VMM会在网络中做一些处理(猜测是发GARP),让后续的客户端请求发往Backup虚机,而不是Primary虚机。同时,Backup的VMM不再会丢弃Backup虚机的输出。当然它现在已经不再是Backup,而是Primary,Backup虚机接管了服务。
如果Backup虚机停止运行,Primary也需要用一个类似的流程来抛弃Backup,停止向它发送事件,系统表现为一个单点的服务。只要有一个因为故障停止运行,并且不再产生网络流量时,Primary和Backup中的另一个都可以上线继续工作。

这里主要是介绍面对故障,P/B切换的逻辑。VMM通过一定时间收不到log信息判断P挂了,之后VMM将backup切换为primary,接收客户端的请求,不在对其进行各种限制:1.直接接收客户端请求处理而不是log channel,2.响应消息不再被VMM丢弃。实际上这里只是大致流程介绍,具体很多细节冲突处理还要看下文。

学生提问:Backup怎么让其他客户端向自己发送请求?
Robert教授:取决于是哪种网络技术,Robert教授认为:每个虚拟机也有一个唯一的MAC地址,当Backup虚机接手时,它会宣称它有Primary的MAC地址,并向外通告说,我是那个MAC地址的主人,之后以太网上的其他人就会向它发送网络数据包。
学生提问:随机数生成器这种操作怎么在Primary和Backup做同步?
Robert教授:VMware FT的设计者认为他们找到了所有类似的操作,对于每一个操作,Primary执行随机数生成,或者某个时间点生成的中断(依赖于执行时间点的中断)。而Backup虚机不会执行这些操作,Backup的VMM会探测这些指令,拦截并且不执行它们。VMM会让Backup虚机等待来自Log Channel的有关这些指令的指示,比如随机数生成器这样的指令,之后VMM会将Primary生成的随机数发送给Backup。论文有暗示说他们让Intel向处理器加了一些特性来支持这里的操作,但是论文没有具体说是什么特性。

4.4 非确定性事件(Non-Deterministic Events)

虽然通常情况下,代码执行都是直接明了的,但并不是说计算机中每一个指令都是由计算机内存的内容而确定的行为。这些指令在Primary和Backup的运行结果可能会不一样。这些指令就是所谓的非确定性事件。设计者们需要弄明白怎么让这一类事件能在Primary和Backup之间同步。
非确定性事件可以分成几类

  • 客户端输入。假设有一个来自于客户端的输入,这个输入随时可能会送达,它是不可预期的。客户端请求何时送达,会有什么样的内容,并不取决于服务当前的状态。我们讨论的系统专注于通过网络来进行交互,这里的系统输入的唯一格式就是网络数据包。当我们说输入的时候,我们实际上是指接收到了一个网络数据包。而一个网络数据包对于我们来说有两部分,一个是数据包中的数据,另一个是提示数据包送达了的中断。**当网络数据包送达时,通常网卡的DMA(Direct Memory Access)会将网络数据包的内容拷贝到内存,之后触发一个中断。操作系统会在处理指令的过程中消费这个中断。对于Primary和Backup来说,这里的步骤必须看起来是一样的,否则它们在执行指令的时候就会出现不一致。**这里的问题是,中断在什么时候,具体在指令流中的哪个位置触发?对于Primary和Backup,最好要在相同的时间,相同的位置触发,否则执行过程就是不一样的,进而会导致它们的状态产生偏差。我们不仅关心网络数据包的内容,还关心中断的时间。

Inputs --> packet --> data + interrupt

  • 有一些指令在不同的计算机上的行为是不一样的,这一类指令称为怪异指令,比如说:
    • 随机数生成器
    • 获取当前时间的指令,在不同时间调用会得到不同的结果
    • 获取计算机的唯一ID
  • 多CPU的并发。我们现在讨论的都是一个单进程系统,没有多CPU多核这种事情。当服务运行在多CPU上时,指令在不同的CPU上会交织在一起运行,进而产生的指令顺序是不可预期的。如果我们在Backup上运行相同的代码,并且代码并行运行在多核CPU上,硬件会使得指令以不同(于Primary)的方式交织在一起,而这会引起不同的运行结果。假设两个核同时向同一份数据请求锁,在Primary上,核1得到了锁;在Backup上,由于细微的时间差别核2得到了锁,那么执行结果极有可能完全不一样,这里其实说的就是(在两个副本上)不同的线程获得了锁。多核是一个巨大的非确定性事件来源。

所有的事件都需要通过Log Channel,从Primary同步到Backup。有关日志条目的格式在论文中没有怎么描述,但是我(Robert教授)猜日志条目中有三样东西:

  1. 事件发生时的指令序号。因为如果要同步中断或者客户端输入数据,最好是Primary和Backup在相同的指令位置看到数据,我们需要知道指令序号。这里的指令号是自机器启动以来指令的相对序号,而不是指令在内存中的地址。比如说,我们正在执行第40亿零79条指令。日志条目需要有指令序号。对于中断和输入来说,指令序号就是指令或者中断在Primary中执行的位置。对于怪异的指令(Weird instructions),比如说获取当前的时间来说,这个序号就是获取时间这条指令执行的序号。这样Backup虚机就知道在哪个指令位置让相应的事件发生。
  2. 日志条目的类型,可能是普通的网络数据输入,也可能是怪异指令。
  3. 最后是数据。如果是一个网络数据包,那么数据就是网络数据包的内容。如果是一个怪异指令,数据将会是这些怪异指令在Primary上执行的结果。这样Backup虚机就可以伪造指令,并提供与Primary相同的结果。

举个例子,Primary和Backup两个虚机内部的guest操作系统需要在模拟的硬件里有一个定时器,能够每秒触发100次中断,这样操作系统才可以通过对这些中断进行计数来跟踪时间。因此,这里的定时器必须在Primary和Backup虚机的完全相同位置产生中断,否则这两个虚机不会以相同的顺序执行指令,进而可能会产生分歧。在运行了Primary虚机的物理服务器上,有一个定时器,这个定时器会计时,生成定时器中断并发送给VMM。在适当的时候,VMM会停止Primary虚机的指令执行,并记下当前的指令序号,然后在指令序号的位置插入伪造的模拟定时器中断,并恢复Primary虚机的运行。之后,VMM将指令序号和定时器中断再发送给Backup虚机。虽然Backup虚机的VMM也可以从自己的物理定时器接收中断,但是它并没有将这些物理定时器中断传递给Backup虚机的guest操作系统,而是直接忽略它们。当来自于Primary虚机的Log条目到达时,Backup虚机的VMM配合特殊的CPU特性支持,会使得物理服务器在相同的指令序号处产生一个定时器中断,之后VMM获取到这个中断,并伪造一个假的定时器中断,并将其送入Backup虚机的guest操作系统,并且这个定时器中断会出现在与Primary相同的指令序号位置。
网络数据包送达时,有一个细节会比较复杂。当网络数据包到达网卡时,如果我们没有运行虚拟机,网卡会将网络数据包通过DMA的方式送到计算机的关联内存中。现在我们有了虚拟机,并且这个网络数据包是发送给虚拟机的,在虚拟机内的操作系统可能会监听DMA并将数据拷贝到虚拟机的内存中。因为VMware的虚拟机设计成可以支持任何操作系统,我们并不知道网络数据包到达时操作系统会执行什么样的操作,有的操作系统或许会真的监听网络数据包拷贝到内存的操作。我们不能允许这种情况发生。如果我们允许网卡直接将网络数据包DMA到Primary虚机中,我们就失去了对于Primary虚机的时序控制,因为我们也不知道什么时候Primary会收到网络数据包。实际中,物理服务器的网卡会将网络数据包拷贝给VMM的内存,之后,网卡中断会送给VMM,并说,一个网络数据包送达了。这时,VMM会暂停Primary虚机,记住当前的指令序号,将整个网络数据包拷贝给Primary虚机的内存,之后模拟一个网卡中断发送给Primary虚机。同时,将网络数据包和指令序号发送给Backup。Backup虚机的VMM也会在对应的指令序号暂停Backup虚机,将网络数据包拷贝给Backup虚机,之后在相同的指令序号位置模拟一个网卡中断发送给Backup虚机。这就是论文中介绍的
Bounce Buffer
机制。
学生提问:如何确保VMware FT管理的服务只使用单核?
Robert教授:VMM暴露给运行了Primary和Backup虚机操作系统的硬件是单核的。
学生提问:这里的操作依赖硬件的定制吗?
Robert教授:是的,这里依赖于CPU的一些特殊的定制,这样VMM就可以告诉CPU,执行1000条指令之后暂停一下,方便VMM将伪造的中断注入,这样Backup虚机就可以与Primary虚机在相同的指令位置触发相同的中断,执行相同的指令。之后,VMM会告诉CPU恢复执行。这里需要一些特殊的硬件,但是现在看起来所有的Intel芯片上都有这个功能,也不是那么的特殊。或许15年前,这个功能还是比较新鲜的,但是现在来说就比较正常了。现在这个功能还有很多其他用途,比如说做CPU时间性能分析,可以让处理器每1000条指令中断一次,这里用的是相同的硬件让微处理器每1000条指令产生一个中断。现在,这是CPU中非常常见的一个小工具。
学生提问:如果Backup领先了Primary会怎么样?
Robert教授: 场景可能是这样,Primary即将在第100万条指令处中断,但是Backup已经执行了100万零1条指令了。如果我们让这种场景发生,那么Primary的中断传输就太晚了。如果我们允许Backup执行领先Primary,就会使得中断在Backup中执行位置落后于Primary。我们不能允许这种情况发生,我们不能允许Backup在执行指令时领先于Primary。VMware FT是这么做的,它会维护一个来自于Primary的Log条目的等待缓冲区,如果缓冲区为空,Backup是不允许执行指令的。如果缓冲区不为空,那么它可以根据Log的信息知道Primary对应的指令序号,并且会强制Backup虚机最多执行指令到这个位置。 Backup虚机的CPU总是会被通知执行到特定的位置就停止。Backup虚机只有在Log缓冲区中有数据才会执行,并且只会执行到Log条目对应的指令序号。在Primary产生的第一个Log,并且送达Backup之前,Backup甚至都不能执行指令,Backup总是落后于Primary至少一个Log。如果物理服务器的资源占用过多,导致Backup执行变慢,那么Backup可能落后于Primary多个Log条目。
学生提问:怪异的指令(Weird instructions)会有多少呢?
Robert教授:怪异指令非常少。只有可能在Primary和Backup中产生不同结果的指令,才会被封装成怪异指令,比如获取当前时间,或者获取当前处理器序号,或者获取已经执行的的指令数,或者向硬件请求一个随机数用来加密,这种指令相对来说都很少见。大部分指令都是类似于ADD这样的指令,它们会在Primary和Backup中得到相同的结果。每个网络数据包未做修改直接被打包转发,然后被两边虚拟机的TCP/IP协议栈解析也会得到相同的结果。我预期99.99%的Log Channel中的数据都会是网络数据包,只有一小部分是怪异指令。对于一个服务于客户端的服务来说,我们可以通过客户端流量判断Log Channel的流量大概是什么样子,因为它基本上就是客户端发送的网络数据包的拷贝。

4.5 输出控制(Output Rule)

对于VMware FT系统的输出,唯一的输出就是对于客户端请求的响应。客户端通过网络数据包将数据送入,服务器的回复也会以网络数据包的形式送出。Primary和Backup虚机都会生成回复报文,之后通过模拟的网卡送出,但是只有Primary虚机才会真正的将回复送出,而Backup虚机只是将回复简单的丢弃掉。
假设我们正在跑一个简单的数据库服务器,这个服务器支持一个计数器自增操作,工作模式是这样,客户端发送了一个自增的请求,服务器端对计数器加1,并返回新的数值。假设最开始一切正常,在Primary和Backup中的计数器都存了10。现在,局域网的一个客户端发送了一个自增的请求给Primary,这个请求在Primary虚机的软件中执行,Primary会发现,现在的数据是10,我要将它变成11,并回复客户端说,现在的数值是11。这个请求也会发送给Backup虚机,并将它的数值从10改到11。Backup也会产生一个回复,但是这个回复会被丢弃,这是我们期望发生的。
如果在一个不恰当的时间,出现了故障会怎样?在这门课程中,需要始终考虑,故障的最坏场景是什么,故障会导致什么结果?
假设Primary确实生成了回复给客户端,但是之后立马崩溃了。现在网络不可靠,Primary发送给Backup的Log条目在Primary崩溃时也丢包了。客户端收到了回复说现在的数据是11,但是Backup虚机因为没有看到客户端请求,它保存的数据还是10。Backup接管服务。这时,客户端再次发送一个自增的请求,这个请求发送到了原来的Backup虚机,它会将自身的数值从10增加到11,并产生第二个数据是11的回复给客户端。两次自增的结果都是11。因为VMware FT的优势就是在不修改软件,甚至软件都不需要知道复制的存在的前提下,就能支持容错,我们也不能修改客户端让它知道因为容错导致的副本切换触发了一些奇怪的事情。
论文里的解决方法就是控制输出(Output Rule),直到Backup虚机确认收到了相应的Log条目,Primary虚机不允许生成任何输出。

  1. 客户端输入到达Primary。
  2. Primary的VMM将输入的拷贝发送给Backup虚机的VMM。有关输入的Log条目在Primary虚机生成输出之前,就发往了Backup。Log条目通过网络发往Backup,但是过程中有可能丢失。
  3. Primary的VMM将输入发送给Primary虚机,Primary虚机生成了输出。现在Primary虚机的里的数据已经变成了11,生成的输出也包含了11,但是VMM不会无条件转发这个输出给客户端。
  4. Primary的VMM会等到之前的Log条目都被Backup虚机确认收到了才将输出转发给客户端。包含了客户端输入的Log条目,会从Primary的VMM送到Backup的VMM,Backup的VMM不用等到Backup虚机实际执行这个输入,就会发送一个表明收到了这条Log的ACK报文给Primary的VMM。当Primary的VMM收到了这个ACK,才会将Primary虚机生成的输出转发到网络中。这里的核心思想是,确保在客户端看到对于请求的响应时,Backup虚机一定也看到了对应的请求,或者说至少在Backup的VMM中缓存了这个请求。这样就不会陷入到这个奇怪的场景:客户端已经收到了回复,但是因为有故障发生和副本切换,新接手的副本完全不知道客户端之前收到了对应的回复。

如果在上面的步骤2中,Log条目通过网络发送给Backup虚机时丢失了,然后Primary虚机崩溃了。因为Log条目丢失了, Backup节点也不会发送ACK消息。如果Log条目的丢失与Primary的崩溃同一时间发生,那么Primary必然在VMM将回复转发到网络之前就崩溃了,客户端也就不会收到任何回复,客户端就不会观察到任何异常,这就是输出控制(Output rule)。
Primary会等到Backup已经有了最新的数据,才会将回复返回给客户端。这几乎是所有的复制方案中对于性能产生伤害的地方。这里的同步等待使得Primary不能超前Backup太多,因为如果Primary超前了并且又故障了,对应的就是Backup的状态落后于客户端的状态。**几乎每一个复制系统都有这个问题,在某个时间点,Primary必须要停下来等待Backup,这对于性能是实打实的限制。**即使副本机器在相邻的机架上,Primary节点发送消息并收到回复仍然需要0.5毫秒的延时。如果我们想要能承受类似于地震或者城市范围内的断电等问题,Primary和Backup需要在不同的城市,之间可能有5毫秒的差距。如果我们将两个副本放置在不同的城市,每次生成一个输出时,都需要至少等待5毫秒,等Backup确认收到了前一个Log条目,然后VMM才能将输出发送到网络。对于一些低请求量的服务,这不是问题。但是如果我们的服务要能够每秒处理数百万个请求,那就会对我们的性能产生巨大的伤害。
如果条件允许,人们会更喜欢使用在更高层级做复制的系统(即应用程序级别的复制,详见4.2复制模型 (what we mean by state))。这样的复制系统可以理解操作的含义,这样的话Primary虚机就不必在每个网络数据包暂停同步一下,而是可以在一个更高层级的操作层面暂停来做同步,甚至可以对一些只读操作不做暂停,但是这就需要一些特殊的应用程序层面的复制机制。
学生提问:VMM这里是具体怎么实现的?
Robert教授:论文也没有说VMM是如何实现的,这里涉及到非常底层的内容,因为包括了内存分配,页表(page table)分配,设备驱动交互,指令拦截,并理解guest操作系统正在执行的指令。
学生提问:其实不用暂停Primary虚机的执行,只需要阻止Primary虚机的输出就行吧?
Robert教授:你是对的,但是不管怎么样,在一个系统中,本来可以几微秒响应一个客户端请求,而现在我们需要先更新另一个城市的副本,这可能会将一个10微秒的操作变成10毫秒。
学生提问:这里虽然等待时间比较长,如果提高请求的并发度,是不是还是可以有高性能?
Robert教授:如果你有大量的客户端并发的发送请求,那么你或许还是可以在高延时的情况下获得高的吞吐量,但是就需要你有足够聪明的设计和足够的幸运。
学生提问:可以不可以将Log保留在Primary虚机对应的物理服务器内存中,这样就不用长时间的等待了。
Robert教授:物理服务器宕机,Log就丢失了。通常,如果服务器故障,就认为服务器中的所有数据都没了,其中包括内存的内容。为了保证系统的可靠性,Primary必须等待Backup的ACK才真正输出。
学生提问:能不能输入送到Primary,输出从Backup送出?
Robert教授:这是个很聪明的想法。我之前完全没有想到过这点。它或许可以工作,我不确定,但是这很有意思。

4.6 重复输出(Duplicated Output)

Backup的VMM返回收到log的ACK,primary响应客户端消息,客户端收到了回复,但是这时Primary虚机崩溃了。Backup接管服务,Backup首先需要消费所有在等待缓冲区中的Log。假设最后一条Log条目对应来自客户端的请求,那么Backup会在处理完客户端请求对应的中断之后,再上线接管服务。这意味着,Backup会将自己的计数器增加到11(原来是10,处理完客户端的自增请求变成11),并生成一个输出报文。因为这时,Backup已经上线接管服务,它生成的输出报文会被它的VMM发往客户端。这样客户端会收到两个内容是11的回复。如果这里的情况真的发生了,那么明显这也是一个异常行为,因为不可能在运行在单个服务器的服务上发生这种行为。
客户端通过TCP与服务进行交互,也就是说客户端请求和回复都通过TCP Channel收发。当Backup接管服务时,因为它的状态与Primary相同,它知道TCP连接的状态和TCP传输的序列号。当**Backup生成回复报文时,这个报文的TCP序列号与之前Primary生成报文的TCP序列号是一样的,这样客户端的TCP栈会发现这是一个重复的报文,它会在TCP层面丢弃这个重复的报文,用户层的软件永远也看不到这里的重复。**这里可以认为是异常的场景,并且被意外的解决了。
事实上,对于任何有主从切换的复制系统,基本上不可能将系统设计成不产生重复输出。为了避免重复输出,有一个选项是在两边都不生成输出,但这是一个非常糟糕的做法(因为对于客户端来说就是一次失败的请求)。当出现主从切换时,切换的两边都有可能生成重复的输出,所有复制系统的客户端需要一种重复检测机制。这里我们使用的是TCP来完成重复检测,如果我们没有TCP,那就需要另一种其他机制,或许是应用程序级别的序列号

学生提问:太长了,听不太清,直接看回答吧。
Robert教授:如果Primary向客户端发送了一个回复报文,之后Primary或者客户端关闭了TCP连接,现在客户端侧是没有TCP连接的。Primary挂了之后,Backup虚机还是有TCP连接的信息。Backup执行最后一条Log,Backup会生成一个回复报文,但是这个报文送到客户端时,客户端并没有相应的TCP连接信息。这里客户端实际会发送一个TCP Reset,这是一个类似于TCP error的东西给Backup虚机,Backup会处理这里的TCP Reset,但是没关系,因为现在只有一个副本,Backup可以任意处理,而不用担心与其他副本有差异。实际上,Backup会直接忽略这个报文。
学生提问:Backup接手服务之后,对于之前的TCP连接,还能用相同的TCP源端口来发送数据吗(因为源端口一般是随机的)?
Robert教授:你可以这么认为。因为Backup的内存镜像与Primary的完全一致,它们会以相同的TCP源端口来发送数据,它们在每一件事情上都是一样的。它们发送的报文每一bit都是一样的。
学生提问:甚至对于IP地址都会是一样的吗,毕竟这里涉及两个物理服务器?
Robert教授:在这个层面,物理服务器并没有IP地址。在我们的例子中,Primary虚机和Backup虚机都有IP地址,但是物理服务器和VMM在网络上基本是透明的。物理服务器上的VMM在网络上并没有自己的唯一标识。虚拟机有自己独立的操作系统和独立的TCP栈,但是对于IP地址和其他的关联数据,Primary和Backup是一样的(类似于HA VIP)。**当虚机发送一个网络报文,它会以虚机的IP地址和MAC地址来发送,这些信息是直接透传到局域网的,而这正是我们想要的。**Backup会生成与Primary完全一样的报文。这里有一些tricky,因为如果物理服务器都接在一个以太网交换机上,那么它们必然在交换机的不同端口上,在发生切换时,我们希望以太网交换机能够知道当前主节点在哪,这样才能正常的转发报文,这会有一些额外的有意思的事情。大部分时候,Primary和Backup都是生成相同的报文,并送出。
(注:早期的VMware虚机都是直接以VLAN或者Flat形式,通过DVS接入到物理网络,虚拟机的报文与物理机无关,可以直接在局域网发送。以太网交换机会维护MAC地址表,表明MAC地址与交换机端口的对应,因为Primary和Backup虚机的MAC地址一样,当主从切换时,这个表需要更新,这样同一个目的MAC地址,切换前是发往了Primary虚机所在的物理服务器对应的交换机端口,切换之后是发往了Backup虚机所在的物理服务器对应的交换机端口。交换机MAC地址表的切换通常通过虚机主动发起GARP来更新。)

4.7 Test-and-Set 服务

除了fail-stop故障,一个非常常见的场景就是,Primary和Backup都在运行,但是它们之间的网络出现了问题,同时它们各自又能够与一些客户端通信(Split Brain)**。**这时,它们都会以为对方挂了,自己需要上线并接管服务。**它们或许会因为接收了不同的客户端请求,而变得不一样。**因为涉及到了计算机网络,那就可能出现上面的问题,而不仅仅是机器故障。
这篇论文解决这个问题的方法是,向一个外部的第三方Test-and-Set服务,来决定Primary还是Backup允许上线。VMware FT需要通过网络支持Test-and-Set服务。这个服务会在内存中保留一些标志位,当你向它发送一个Test-and-Set请求,它会设置标志位,并且返回旧的值。Primary和Backup都需要获取Test-and-Set标志位,这有点像一个锁。为了能够上线,它们或许会同时发送一个Test-and-Set请求,给Test-and-Set服务。当第一个请求送达时,Test-and-Set服务会说,这个标志位之前是0,现在是1。第二个请求送达时,Test-and-Set服务会说,标志位已经是1了,你不允许成为Primary。对于这个Test-and-Set服务,我们可以认为运行在单台服务器。当网络出现故障,并且两个副本都认为对方已经挂了时,Test-and-Set服务就是一个仲裁官,决定了两个副本中哪一个应该上线。

学生提问:只有在网络故障的时候才需要询问Test-and-Set服务吗?
Robert教授:在所有情况下,两个副本中任意一个觉得对方挂了,想要上线的那个副本仍然需要获得Test-and-Set服务的锁。**在6.824这门课程中,有个核心的规则就是,你无法判断另一个计算机是否真的挂了,唯一知道的只是无法从那台计算机收到网络报文,但无法判断是因为那台计算机挂了,还是因为网络出问题了导致的。**Backup看到的是,我收不到来自Primary的网络报文,或许Primary挂了,或许还活着。Primary或许也同时看不到Backup的报文。如果存在网络分区,那么必然要询问Test-and-Set服务,实际上没人知道现在是不是网络分区,每次涉及到主从切换,都需要向Test-and-Set服务进行查询。当副本想要上线的时候,Test-and-Set服务必须要在线,因为副本需要获取这里的Test-and-Set锁。现在Test-and-Set看起来像是个单点故障(Single-Point-of-Failure)。虽然VMware FT尝试构建一个复制的容错的系统,但是最后,主从切换还是依赖于Test-and-Set服务在线,这有点让人失望。我强烈的认为,Test-and-Set服务本身也是个复制的服务,并且是容错的

参考文献:
https://pdos.csail.mit.edu/6.824/schedule.html
https://mit-public-courses-cn-translatio.gitbook.io/mit6-824/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值