MIT 6.824 分布式系统课程第四课:主备复制

Posted by 启示录 Blog on March 28, 2020

笔记: Lecture 4: Primary/Backup Replication

视频:Lecture 4: Primary-Backup Replication

论文地址:The design of a practical system for fault-tolerant virtual machines

课程概要

业界容错的解决方案之一是主备复制,通过学习VMware FT看看具体如何实现,以及主备遇到的问题。

正文

容错的目的

  • 保证服务的可用性
  • 服务器和网络都会出现故障,但是使用副本容错还是必不可少

复制副本并不是银弹

  • 单个副本的容错

    风扇停止运行、CPU超载导致主机停机、电源线拔了、光缆被挖。因为磁盘空间不足导致软件停止。

  • 硬件缺陷、软件bug、或者是配置错误。这些可以导致一时间所有的副本都宕机。(其实配置问题只需要增加校验的步骤也可以解决)
  • 出现地震或者是全城停电。(这里要有异地副本)

复制副本的开销如何?带宽、磁盘、额外的服务器

目前两种主要的复制方式:

  • 状态复制

    主节点负责执行写、写完之后发送最新的状态给副本

  • 复制状态机

客户端发送状态至主节点,主节点按顺序执行并且发送给副本。所有的副本执行相同的动作。相同的开始状态、操作、顺序、最终态状态复制传输比较简单,方式状态可能会比较多,网络传输速度太慢

复制状态机往往用的网络更少,它的特征主要是进行状态比较,但是对于保证正确性需要做很多工作。VM-FT就是使用这个模式

本课重点

  • 复制什么状态
  • 主节点是否需要等待备节点
  • 什么时候进行主备切换?
  • 主备切换时异常如何处理?
  • 如何快速的进行主备切换?

在生产环境中,主备的同步要到什么程度?

  • 应用状态的同步,eg:数据库表。GFS是这种方式,主节点会把高优先级的操作发送给副本(譬如:文件写入。计算机时钟中断则不同步)。应用代码需要理解容错,对于流的新旧要校验
  • 机器级别,eg:寄存器和RAM内容都同步

    需要我们同步复制主节点所有的操作(中间过程不再加工数据),机器事件也会转发(中断、DMA内容、&c),事件流保持完整同步。除非是机器差异产生的差别。对于指令并不是真正意义上的执行该指令,而是应用通过指令得出最后的结果。这一切是在软件层面完成

VMware FT属于机器级别的状态复制,可以运行在不通架构的服务器和系统之上(兼容),对于客户端来说整体还是单体操作系统,无任何感知保持透明。

论文概览

FT的架构

FT通信协议

术语:

hypervisor==monitor(监控)== VMM(虚拟机监控)

O/S+app指代在虚拟机中运行的应用程序(操作系统、应用软件)

两台机器,一台主,一台副本

主节点通过网络(日志通道log channel)发送所有的外部事件(客户端包)至副本,日志是有顺序的。当主备其中某一个出现故障时,都会变成单机,如果是备会变为主,此时无副本。如果是备出现故障,主的事件会丢失。

VMM会模拟本地磁盘接口,虚拟机操作文件时。与访问实际磁盘的调用一致。但实际上存储在网络存储上,通常只有主和存储服务器通信(副本只是读取),当副本变为主节点时才对存储进行通信。因为是存储在统一的物理磁盘上,在副本出现故障时,新的副本不需要拷贝数据,就能很快的启动。

主节点何时必须像副本发送信息?

当出现可能导致会产生不一致的时候,就需要立即发送(例如文件更新)。任何导致结果不一致的不确定指令也需要同步。

有哪些动作需要FT介入处理?

当内存和寄存器相同时,大多数的指令在主备上各自的结果都一致。但是有些不确定的指令就需要FT处理,例如来自外部的输入事件——网络数据包、DMA数据+中断、时钟中断、非状态指令(读取当前时间、随机数)、多核并行任务的执行(多线程在多次运行时对锁的抢占顺序是会不同)。

当出现主备出现分歧时,会导致什么后果?

副本的b/c状态与主节点的状态不一致,如果此时出现主节点宕机,客户端就会看到数据不一致。

例子:GFS租约过期

假设GFS的master是有副本,chunkserver在租约过期前的60s就发送续期指令。(时钟中断管理服务器时间)

在master上,收到请求后发生时钟中断。此时主节点对chunkserver进行续约

在backup上,时钟中断在请求之前发生,此时副本记录的chunkserver已经过期了。

假设此时主节点崩溃,失效的主节点被副本接管。副本发现之前的chunkserver已经过期了,需要重新选择新的chunkserver。那么此时在系统中就会出现两个chunkserver都持有合法的租约。

因而要求:副本要和主节点所有事件都同步、顺序一致、保持指令流的一致性。

FT的日志包含三部分:指令、类型、数据

FT是如何处理时钟中断的?

理想状态:主备在同一事件流所看到的指令是一致的。

主:

  1. FT发生时钟中断
  2. FT从CPU中读取指令编号
  3. FT发送指令X的时钟中断到日志通道(log channel)
  4. FT 分发中断给主节点,然后恢复正常

这些依赖CPU需要支持在执行X条指令后发生时钟中断

备:

  1. 忽略自己的时钟中断
  2. FT获取所有日志条目之前,未执行的指令
  3. FT告诉CPU在指令X时,进行中断
  4. FT模拟计时器中断,进行备份操作

FT是如何处理网络包的(请求包)?

主:

  1. FT告诉网卡(NIC),拷贝一份数据包到FT的私有回弹缓冲区(bounce buffer)
  2. NIC有时会执行完DMA后才进行中断
  3. FT捕获到中断
  4. FT暂停主节点
  5. FT复制刚刚第一步存储在bounce buffer的数据到主节点内存
  6. FT在主节点中模拟NIC中断
  7. FT发送网络数据包和指令#到副本

备:

  1. FT从log stream中 获取到数据和指令#
  2. FT通知副本CPU在指令X处中断
  3. FT拷贝网络包数据到副本内存中,并且在副本中模拟NIC中断

为什么会引入bounce buffer?

主要是为了数据在主备节点中,能在合适的时间得到处理,而不会接收到数据包就开始处理,不利于回放。

注意:副本需要滞后一个日志记录处理

假设主节点在指令X之后,进来一个中断或者是输入。备份服务器在获得指令X后就开始了执行,那么此时的输入的结果就无法在副本中重放,因为副本的已经执行完了指令X,而新进来的输入或者是中断需要等待下一个指令来结束。(类似文件结束符)

举例:非确定指令

在现实生产环境中,即使主备的状态一致,但是还是会出现相同的指令产生不同的结果。例如:读取当前时间、随机数、处理器序列号、时钟周期

主节点执行指令的流程:

  1. 主节点执行指令,FT调用CPU执行中断
  2. FT执行指令并且记录结果
  3. 发送结果和指令给副本节点

副本节:

  1. FT读取日志,根据指令生成中断
  2. FT根据主节点需要的结果返回信息

执行结果响应流程:

  1. 主备节点执行指令后都会输出结果
  2. 主节点的输出结果为实际结果
  3. 备节点的结果会被忽略(只作为主节点返回结果的准许)

执行结果响应案例:数据库服务器

客户端发送“自增”请求给数据库,数据库实行自增后存储数据,并返回新的值给客户端。

  1. 主节点存储的值是10
  2. 客户端发起自增请求
  3. FT分发请求到主备节点
  4. 主节点增加到11,并响应结果给FT,FT响应回客户端
  5. 副本节点执行,增加到11,并响应给FT
  6. 客户端得到结果11

但是:

假设主节点在发送结果后宕机,客户端得到的结果是11

logging channel丢失了客户端的写请求,因为主节点已经宕机不会再次发送

副本会变为主节点,此时副本内的值还是10。

客户端此时发起一个“自增”请求,得到的结果不是12,而是11。

解决方式:改变结果的输出规则(论文2.2)

主节点发送结果之前,必须先收到副本的响应才能发送结果

主节点:

  1. 收到客户端的自增请求
  2. 发送客户端请求到logging channel
  3. 主节点缓存当前结果
  4. 等待副本响应已经收到日志
  5. 响应结果给客户端

假设主节点收到副本响应前后在某个时间点宕机:

  1. 在收到副本响应前宕机

副本是看不到客户端请求的,并且不会自增。主无应答

  1. 在收到副本响应后宕机

    客户端可能看到“11”的响应结果,副本肯定已经收到客户端的写请求。并且值为11

结果响应规则是一个trade off问题,在所有的复制系统中都有可能出现。它会直接影响系统的性能。有时是可以取舍的,例如在等待响应前,结果为只读操作,得到响应后才可以再次修改。而FT是非应用级别响应,这里需要等待副本响应结果。

论文讨论

Q:如果主节点在收到副本节点响应后立即宕机(还未返回给客户端),那么客户端是否永远等待响应结果?

A:当主节点宕机,副本提升为主节点时,会出现以下情况:

  1. 副本会消化完日志流中的数据
  2. 消化日志时所产生的输出被丢弃
  3. 日志消化完后,副本变为主节点,此时结果不再丢弃

在例子里面,最后一条日志是客户端的请求指令,当客户端请求结果时,所看到的值是最新的值,这个结果有新晋升为主节点的副本返回

Q:假设主节点在返回结果后宕机,副本会不会返回两次?

A:这个是有可能的,如果是TCP,那么会收到重复序号的数据包。如果是写磁盘,会再写一份同样的数据到相同的块。

在复制系统中,主副本替换产生两次结果响应是很常见的情景,客户端需要让状态具有幂等性。相同的请求,多次执行结果不变。

Q:假设FT产生的网络分区,是否会导致“脑裂”?如果主节点和副本都假设对方已经宕机,他们是否都变为主节点?

A:共享存储的磁盘服务已经解决了这个问题,磁盘服务支持原子TSL(原子检查并设置)操作,主副节点遇到对象已经宕机,都会试图进行test-and-set操作,如果只存在一个存活,在进行test-and-set后并上线,但是假设两者都试图修改,其中有一方会失败,失败的晋升请求会被忽略。

不过磁盘服务器可能会有单点故障问题,磁盘服务宕机,整个服务也会宕机。这里可能需要引入支持复制的磁盘服务器

Q:为什么不支持多核处理器?

A:并行执行,无法保证能达到机器级别的指令执行结果保持统一

性能(图表1)

FT/非FT:性能差别较小

日志带宽:MySQL的磁盘+网络传输可以达到18Mbits/秒

总体来看,这些结果其实比较偏低。一块SSD磁盘可以达到400Mb/秒,这个数据看起来是这些应用不怎么依赖磁盘

FT适合应用于什么场景?

关键但压力低的服务,例如域名服务器。其软件的修改比较低的服务

吞吐量大的服务如何选择复制?

在工业界,常见使用的复制是应用级别的复制,复制状态机。例如数据库。在数据库中,状态只有DB,而不是这台服务器内存+磁盘的所有数据。对应的事件是get和set操作,而不是数据包和中断。

优势在于更少的颗粒度同步,并且开销也小。GFS使用的是应用级别的复制,Raft也是为应用级别而诞生的

总结

主备复制这个常见,VM-FT讲述的很清晰,适合学习复制是什么。但是FT是单点的,会有单点故障的风险。如果是为了性能,应选用应用级别的复制状态机。

备注

听过VM已经支持了多核CPU,FT已经被废弃。

What’s New in vSphere 6.0: Multi-CPU Fault Tolerance

ReTrace: Collecting Execution Trace with Virtual Machine Deterministic Replay

参考资料