6.824 分布式系统 Fault-Tolerant Virtual Machines
2023-10-05 18:15:00 # Papers

介绍

实现容错的方法

  1. 主从备份: 主服务器的所有状态都发送给备份, 这样非常消耗带宽
  2. 状态机方法: 将服务器建模为确定性状态机, 通过按照相同初始化状态启动和以相同顺序接收相同的输入来保持同步

    但是大多数的服务器都有不确定的操作(比如读取时钟时间), 所以还需要一些额外的协作来保证同步, 这在物理机上非常困难

运行在管理程序上的 VM 是实现额外协作的很好方法

管理程序有 VM 的全权控制权, 所以它能知道 VM 上所有不确定的操作

image

基本的 FT 设计

VMs 的虚拟磁盘是在共享存储中的, 可以接收主备服务器的输入输出

只有主 VM 会说明它在网络中的存在, 所有的网络输入和其他设备输入都会来到主 VM 上

所有主 VM 收到的输入都会通过名为 logging channel 的网络连接

为了处理不确定操作的额外协作也会被发到备份 VM 中, 备份 VM 与主 VM 使用相同的方式执行非确定性操作

备份 VM 的输出会被忽略, 之后主 VM 的输入会被返回到客户端

通过相关服务器的心跳机制和监测 logging channel 的流量从而检测主备服务器是否失效

确定性重放实现

三个挑战

  1. 正确得到所有输入和非确定性执行的操作
  2. 正确地让输入和非确定性操作在备份 VM 上执行
  3. 不引起性能退化

非确定性操作

  1. 来自客户端的输入
  2. 非确定性指令: 随机数, 获取时间
  3. 多核并行引发的指令交错执行(本论文未解决这个问题)

FT 协议

输出要求: 备份 VM 接管主 VM 之后, 备份 VM 将与主 VM 所有的输出相同

特殊情况: 主 VM 在输出之后立即故障, 备份 VM 未执行到相同输出指令就被中断

输出规则: 主 VM 延后输出(不会停止处理指令), 直到 备份VM 已经接收并确认产生了与输出相关的日志

image

故障情况

  1. 主 VM 在收到 ACK 之前故障, 它不会返回结果给客户端
  2. 主 VM 在收到 ACK 之后故障, 备份 VM 在接管后也发送, 客户端会收到两次输出

    但是 TCP 连接会处理重复的数据包, 磁盘会对同一块区域重复写入

检测和故障响应

  1. 主 VM 故障: 备份 VM 重放日志, 重放结束之后上线成为 主 VM
  2. 备份 VM 故障: 主 VM 停止在 logging channel 上发送日志, 主 VM 继续执行

检测故障方式

  1. UDP 心跳检测
  2. 监控 logging channel
  3. 备份 VM 发送给 主 VM 的确认信息

脑裂问题: 备份 VM 认为 主 VM 故障, 自己上位, 这样可能会出现两个主 VM

解决问题: 磁盘服务器设置一个 flag, 第一个访问(原子操作)的 VM 会成为 主 VM

FT 的实际执行

启动一个备份 VM

  1. FT VMotion 直接对 VM 克隆并简历 logging channel
  2. 实现监控并管理集群资源的服务, 可以选择一个宿主机来启动新 VM

image

  1. 主 VM 执行时, 会将 log entry 输出到 log buffer 中, 如果 log buffer 已满, 主VM 等待
  2. 主 VM 的 log buffer 尽快将内容输送到 logging channel
  3. log entry 被读到 备份 VM 的 log buffer
  4. 备份 VM 接收 log buffer, 如果为空则等待
  5. 备份 VM 发送 ACK 给 主 VM

此外在发送 log entry 的时候, 会发送附加信息来确定实时延迟

根据 CPU 资源的调度来调整延迟

VM FT上的操作

  1. 关机, 主 VM 关机了 备份 VM 也要关机
  2. 资源管理: 如 CPU 频率
  3. VMotion: 运行前暂停所有 IO 操作

磁盘 IO

异步发生的磁盘读写操作给系统带来不确定性: 对于有竞争的磁盘操作, 强制为顺序执行

内存在读取硬盘, CPU 在操作内存:

  1. 给那段内存加保护, VM 读取在硬盘读取之后, 在 MMU 中改变页的保护
  2. bounce buffer: 硬盘读写要经过一块缓存

IO 进行时, 主 VM 故障, 备份 VM 不知道是否发出 IO 请求:

如果日志中没有 IO 造成的中断, 备份 VM 重做 IO 操作, 幂等操作不影响结果

网络 IO

VMware 对虚拟机的网络做了优化, 管理程序会异步更新 VM 的网络状态

(异步: 在 VM 正在运行的时候也可以更新网络状态)

(同步: VM 需要暂停, 等待管理程序更新网络状态之后再运行)

但是我们要保证这些更新在 主 VM 和 副 VM 上更新的时间一致

解决方法: 关闭异步更新, 管理程序记录网络变化, 并应用到备份 VM

  1. 减少 陷阱和中断: 一些包产生一个中断 而不是一个包产生一个中断
  2. 减少传包的延时, TCP 数据一到就开始处理, 省去上下文切换的开销

替代设计

共享和非共享磁盘

非共享磁盘:

优点

  1. 主 VM 的磁盘写入不必被延迟
  2. 非共享磁盘造价更低
    缺点
  3. 发生故障之后还要同步磁盘状态
  4. 需要远程服务器决策来解决脑裂情况

备份 VM 执行磁盘读

备份 VM 正常不会在 磁盘上读取东西, 这被视作输入从 logging channel 读入

备份 VM 执行磁盘读可以降低 logging channel 上的流量

但是会产生许多同步问题, 还要处理容错