文章目录
- 这是阅读论文《The Design of a Practical System for Fault-Tolerant Virtual Machines》的笔记,也是MIT6.824课程的第四课要求阅读的论文。这篇论文是VMware发表,讲述的是实施的一个商业企业级系统,用于提供容错虚拟机。该系统基于通过另一台服务器上的备份虚拟机复制主虚拟机执行的方法。
1. 论文概述
实现分布式容错的一种常见方法是主/备份方法。从而可以在主服务器挂掉时,让备份服务器补上。
主备份服务器需要保持一致,对于主/备份方法中保持同步的方法有两种:
-
State transfer(状态转移):主服务器持续将所有状态(包括CPU、内存和I/O设备)变化发送给备份服务器。此方法传输的数据量大,所需的带宽非常大。
-
Replicated State Machine(备份状态机):将备份状态机视为确定状态机(Deterministic State Machine,DSM)。然后主/备份服务器都以相同的初始状态启动,然后以相同的顺序接收并执行相同的输入请求,然后得到相同的输出,这样就可以保持两者状态的一致。此方法较复杂,但传输的数据量小很多。(本文就是采用此方法)
-
采用备份状态机会有一个问题,即对于真实物理机来讲,有些行为是不确定的(例如,中断,产生的随机数等),所以很难将行为看作是一个确定性(deterministic)的行为。
VMWare的解决方案是将所有操作虚拟化,并在VM和物理机之间加一个Hypervisor(虚拟机管理程序),然后就可以通过hypervisor让VM都能模拟成一个DSM运行,那么primary的所有操作都确定了,再通过Logging channel将这些操作传递到backup,然后backup进行replay,从而实现两者的高度一致。
具体是怎么将不确定的行为进行确定化操作的,它主要是进行了一个写日志的操作来保证的,后续会详细解释。
2. 系统架构
2.1 VMWare FT的结构图
- VMWare的结构是运行在同一个网络下,两个虚拟机部署在不同的机器上,并且共享一个磁盘(这里会有一个split-brain问题,即primary 和 backup 之间通信断开,但此时 primary 还在运行,若 backup 此时上线,会造成两者同时执行的问题,可能会导致数据损坏 )。Primary接收的输入信息是通过Logging channel传输给Backup,以保持同步。
对于外界,它们只知道有一个Primary VM在工作,并且所有的输入输出都是由Primary处理。
物理机和VM之间有一个虚拟机管理程序Hypervisor,即virtual machine monitor,VMM。
VMM对硬件进行模拟和控制可以捕获到不确定的输入的所有相关信息,从而可以在后续让backup可以replay这些不确定的输入。
2.2 replay(确定性重放)
-
确定性重放是指,对于primary执行的操作,backup以相同的确定行为方式执行,简单讲就是backup执行和primary一样的操作。
-
对于一个真实物理机,将其看作是确定状态机(DSM)有三点挑战:
- 需要正确捕获所有的输入和不确定操作,以保证能在backup上进行确定性的执行;
- 在backup上正确地执行所有的input和不确定操作;
- 保证1,2下,还要保证性能。
-
对于replay,要解决的一个重要的问题是primary的不确定操作在backup的确定性执行。
解决这个问题是利用了日志。primary的所有确定性操作和不确定事件的所有状态都会记录在log entry流中,通过Logging channel发送给backup并使其replay。 -
VMWare利用Hypervisor将所有操作虚拟化,使得做到了上述三点。实现的最终结果是,primary 会将它所有的 input 以及所有可能会发生不确定性结果的相关状态全部会记录到日志中,这个日志会交给 backup 进行 replay 操作,能够确保 backup 进行 replay 后同 primary 的状态是一模一样的。
举个例子,一个操作让 primary 生成一个随机数,那么 primary 会在日志中记录当前生成这个操作的所有状态,比如它是根据当前时间或者是当前某个时钟周期当作 seed,这些随机性全部由 hypervisor 来处理,backup 进行日志 replay 时,碰到这种随机性事件,hypervisor 让它执行的时候跟 primary 得出的结果一模一样,让两者在状态上没有差别,很了不起。
2.3 FT Protocol
- 此协议应用于Logging channel,它的基本要求是:
若primary宕机了,backup接替它的工作,backup之后向外界发送的所有的output要和primary原本应当发送的一致。 - 可能会发生一些特殊情况:
若primary在执行输出操作后立即故障,backup在接管之前可能还没有执行到同样的输出操作,然后就被不确定的事件(如,计时中断)影响,这样backup就无法以与primary发生故障时的相同状态上线,所以提出了Output Rule。 - 为了保证上述要求,设计输出规则(如上图):
- primary在所有关于本次Output的信息都发送给backup后(并且要确保backup收到,backup会发送一个ACK),才会把output发送给外界。
- primary只是推迟将output发送给外界,不会暂停执行后面的任务(异步执行)。
- 如图,简单来说,就是primary收到一条信息,并且这条信息是需要回复的(即,要output),那么primary先会写日志并且传给backup,backup收到以后发送一个确认收到的ACK给primary,然后primary才会执行output。
- 但是,这种方法不能保证Exactly once(只发送一次),因为若primary在收到backup的ACK之后,已经发出了output,但是此时挂掉了,然后backup顶上去之后不能判断是否是在发送了output之后宕机的,所以它会再发一次。这个问题容易解决:
- output是通过网络进行发送的,例如TCP之类的网络协议能够检测重复的数据包;
- 对于一个写操作,它就是两次在同一个位置写,也不影响结果。
2.4 FT Logging Buffers and Channel
- primary在各自生产和消费日志的时候它们不是将日志写到磁盘然后再读。primary和backup它们各自会有一个log buffer缓存,primary将产生的日志写入log buffer,然后通过Logging channel传到backup的的log buffer中,backup再从自己的缓存中读取日志并replay。
- 这里产生的问题是一个log buffer满了,一个log buffer空,即消费者和生产者处理日志的速度出现差距,导致backup处理太快而没有了日志处理,或backup处理太慢导致primary中的缓存已经满了,导致后面primary和backup差距越来越大。整个系统是不希望出现这样的情况的,因为如果 primary宕机了,backup 是需要完成 replay 才能顶上,差距大了,backup 就需要耗费比较长的时间追赶上,这样的话意味着系统的响应是不及时的。
- 为此系统设计了一个机制,使得primary和backup之间的差距保持在一个范围内。即,例如当primary产生日志过快和backup之间的延迟超过了这个范围,就降低primary的CPU资源让primary产生日志的速度慢一点,待backup追上后再提高primary的CPU资源。
2.5 监测和故障响应
- 对于监测,primary和backup的服务之间会有UDP的heartbeat来监测对方是否是挂了,也会监控Logging channel的流量和backup发送给primary的ACK。若心跳和日志流量停止的时间超过了超时时间的阈值,就会声明故障。
- 这里有一个问题就是之前提到过的split-brain问题。backup长时间没有收到来自primary的heartbeat,此时可能是宕机了,可能是网络问题,这时backup是不能直接顶上去的,因为若primary没有宕机,那么此时就会有两个primary,如果它们都去操作共享存储可能会出现数据损坏。
对于这个问题,VMWare FT的解决方式是test-and-set的原子操作,它们会有一个flag,然后去拿到这个flag才可以操作磁盘数据,类似于锁。 - 对于test-and-set操作,类似于下面这样的伪代码,对一个flag进行原子操作:
test-and-set() {
acquire lock()
if flag == true:
release lock()
return false
else:
flag = true
release lock()
return true
}
2.6 虚拟机恢复
- 虚拟机primary和backup都可能会失效,所以为了架构的高可用性,VMWare提出了一个技术FT VMotion,用来负责backup的创建。它能够直接对一个VM进行克隆,并且在完成克隆后会建立好和primary的Logging channel,被克隆一方是primary,另一个就是backup。
- 此外,VMware vSphere 还实现了一个可以监控并管理集群资源的服务,可用于选取适合启动新虚拟机的宿主机。
2.7 额外的选择
- VMWare在已有的设计之外,给出了别的方案,比如不使用共享存储,而是primary和backup都有自己的存储。因为在实际的部署时,primary和backup的服务要架设在不同的区域,使用共享存储的方案就会比较低效。但是,各有自己的存储就会有一个存储数据的一致性问题,除此之外还有split-brain问题。
3. VM-FT与GFS的容错性比较
- VM-FT备份的是计算,GFS备份的是存储。
- VM-FT提供了相对严谨的一致性,并且对客户端和服务器都是透明的。可以用它为任何已有的网络服务器提供容错。例如,可以将 FT 应用于一个已有的邮件服务器并为其提供容错性。
- GFS 只针对一种简单的服务提供容错性,它的备份策略会比 FT 更为高效。例如,GFS 不需要让所有的操作都应用在所有的 Replica 上。
VMware 提出的这套 Fault-Tolerant 方案可以用在许多系统中。但是,它依然不适合进行高吞吐量的服务,毕竟它要对整个系统内的内存、磁盘、中断等都进行 replay,这是一个巨大的负担。
参考
[1] 容错虚拟机分布式系统的设计
[2] VM-FT 论文研读
[3] Lecture 4: Primary-Backup Replication
[4] Fault-Tolerant Virtual Machines 论文解读