浅谈分布式一致性协议| 青训营笔记

114 阅读8分钟

浅谈分布式一致性协议| 青训营笔记

这是我参与「第四届青训营 」笔记创作活动的第5天,主要是对上课时的内容进行汇总,通过记笔记对知识的再次学习。

分布式系统

分布式系统面临的挑战

  • 数据规模越来越大
  • 服务的可用性要求越来越高
  • 快速迭代的业务要求系统足够易用

理想的分布式系统

  • 高性能:可拓展、低时延、高吞吐
  • 正确:一致性、易于理解
  • 可靠:容错、高可用

从HDFS开始

image.png

案例-KV

  • 从最简单的kv开始

  • 接口:

    • Get(key)->value
    • BatchPut([k1,k2,...],[v1,v2,...])
  • 第一次实现

    • RPC
    • DB Engine
  • 可靠性

    • 容错
    • 高可用
  • 正确性:

    • 单进程,所有操作顺序执行

一致性与共识算法

从复制开始

一台机器会挂,就采用多个机器,但如果多个副本都能接收请求,存在不一致

如何复制

  • 主副本定期拷贝全量数据到从副本
  • 主副本拷贝操作到从副本

如何复制操作

  • 主副本把所有的操作打包成Log

    • 所有的Log写入都是持久化的,保存在磁盘上
  • 应用包装成状态机,只接收Log作为Input

  • 主副本确认Log已经成功写入到副本机器上,当状态机apply后,返回客户端

关于读操作

  • 读操作

    • 方案一:直接读状态机,要求写操作进入状态机后再返回client
    • 方案二:写操作复制完成后直接返回,读操作Block等待所有pending log进入状态机
  • 如果不遵循上述两周方案呢?

    • 可能存在刚刚写入的值读不到的情况(在Log中)

什么是一致性

  • 对于我们的KV

    • 像操作一台机器一样
      • 要读到最近写入的值
  • 一致性是一种模型(或语义)

    • 来约定一个分布式系统如何向外界(应用)提供服务
    • KV中常见的一致性模型
      • 最终一致性:读取可能暂时读不到但是总会读到
      • 线性一致性:最严格,线性执行(最理想的)

复制协议-当失效发生

  • 当主副本失效
    • 手动切换

    • 容错?

      • 不,我们的服务还是停了
    • 高可用?

      • 也许,取决于我们从发现到切换的过程的有多快
    • 正确?

      • 操作只从一台机器上发起
      • 所有操作返回前都已经复制到另一台机器上了

共识算法

  • 什么是共识算法

    • 简而言之一个值一旦确定,所有人都认同
  • 有文章证明是一个不可能的任务

  • 错误总是发生

    • Non-Byzantine fault
  • 错误类型很多

    • 网络断开,分区,缓慢,重传,乱序
    • CPU、IO都有几率停
  • 容错

  • 共识协议不等于一致性

    • 应用层面不同的一致性,都可以用共识协议来实现
      • 比如可以故意返回旧的值

    简单的复制协议也可以提供线性一致性

  • 一般讨论共识协议时提到的一致性,都值线性一致性

    • 因为弱一致性往往可以用相对的简单的复制算法实现

一致性协议案例:Raft

Paxos

  • The Part-Time Parliamen by Lamport 1989
    • 也就是人们提供的Paxos
    • 基本上就是一致性协议的同义词
    • 该算法的正确性是经过证明的
  • 那么问题解决了?
    • Paxos是出了名的难以理解,Lamport本人在01年又写了一篇Paxos Made Simple
      • "The Paxos Algorithm,when presented in plain English,is very simple."
    • 算法整体是以比较抽象的形式描述,工程实现时需要做一些修改
    • Google 在实现Chubby的时候是这样描述的
      • here are significant gaps between the description of the Paxos algorithm and the needs of real-world system... the final system will be based on an unproven protocol.

Raft

  • 2014年发表
  • 易于理解作为算法的设计目标
    • 使用了RSM、Log、RPC的概念
    • 直接使用了PRC对算法进行了描述
    • Strong Leader-based
    • 使用了随机的方法减少约束
  • 正确性
    • 形式化验证
    • 拥有大量成熟系统

复制状态机(RSM)

  • RSM(replicated state machine)

    • Raft 中所有的 consensus 都是直接使用 Log 作为载体
  • Commited Index

    • 一旦 Raft 更新 Commited Index,意味着这个Index 前的所有Log 都可以提交给状态机了
    • Commited Index 是不持久化的,状态机也是volatile的,重启后从第一条Log开始

Raft 角色

image (1).png

Raft Term

  • 每个Leader服务于一个term
  • 每个term至多只有一个leader
  • 每个节点存储当前的term
  • 每个节点term从一开始,只增不减
  • 所有rpc的 Request Reponse 都携带term
  • 只Commit本term 内的log

Raft 主节点失效

  • Leader 定期的发送AppendEntries RPCs 给其余所有节点

  • 如果Follower 有一段时间没有收到 Leader 的 AppendEntries,则转换身份成为 Candidate

  • Candidate 自增自己的 term,同时使用 RequestVote RPCs 向剩余节点请求投票

    • raft 在检查是否可以投票时,会检查 log 是否 outdated,至少不比本身旧才会投给对应的Candidate
  • 如果多数节点投给它,则成为该term 的 Leader

Raft 安全性 - 同 Term

  • 对于Term 内 的安全性

    • 目标:
      • 对于所有已经非commited 的 <term, index> 位置上至多只有一条log
  • 由于Raft 的多数派选举,我们可以保证在一个term 中只有一个leader

    • 我们可以证明一条更严格的声明:在任何<term,index> 位置上,至多只有一条log

Raft 安全性 - 跨 Term

  • 对于跨Term 的安全性

    • 目标:
      • 如果一个log被标记 Commited,那这个log 一定会在未来所有的leader 中出现 Leader completeness
  • 可以证明这个 property

    • Raft 选举时会检查 Log 的 是否 outdated,只有最新的 才能当选Leader
    • 选举需要多数派投票,而commited log 也已经在多数派中(必有 overlap)
    • 新Leader 一定持有 commited log,且Leader 永远不会 overwriter log

Raft 安全性验证

  • 真的安全吗
    • Raft使用 TLA+ 进行了验证
      • 形式验证(Formal Method),以数学的形式对算法进行表达,由计算机程序对算法所有的状态进行遍历

回到KV

案例 - KV

  • 利用 Raft 算法,重新打造我们的KV

  • 回顾一下一致性读写的定义

    • 方案一:

      • 写log被 commit 了,返回客户端成功
      • 读操作也写入一条log,状态机apply 时返回 client
      • 增加 Log 量
    • 方案二:

      • 写log被commit 了,返回客户端成功
      • 读操作先等待所有commited log apply,再读取状态机
      • 优化写时延
    • 方案三:

      • 写Log 被状态机apply,返回给 client
      • 读操作直接读状态机
      • 优化读时延
  • Raft 不保证一直有一个leader

    • 只保证一个term至多有一个leader
    • 可能存在多个term的leader
  • Split-brain

  • 确定合法的Leadership

    • 方案一:
      • 通过一轮Heartbeat 确认 Leadership (获取多数派的响应)
    • 方案二:
      • 通过上一次Heartbeat 时间 来保证接下来的有段时间被 follower 不会 timeout
      • 同时 follower 在这段时间内不进行投票
      • 如果多数 follower 满足条件,那么在这段时间内则保证不会有新的Leader 产生
  • 结合实际情况选择方案二或方案三

    • 取决于 raft 的实现程度以及读写的情况
  • 多个副本只有单个副本可以提供服务

    • 服务无法水平拓展
  • 增加更多Raft 组

    • 如果操作跨 Raft 组
  • Raft: 关于Log

    • 论文中就给出的方案,当过多的Log 占用后,启动snapshot,替换掉 Log
    • 如果对于持久化的状态机,如何快速的产生 Snapshot
    • 多组 Raft的 应用中,Log如何合流
  • 关于 configuration change

    • 论文中给出的 joint-consensus 以及单一节点变更两种方案

回到共识算法

  • Raft 是正确的,但是在工程世界呢?

    • 真实世界中不是所有的错误都是完美 fail-stop的
    • cloudflare 的 case,etcd 在 partial network下 ,outage 了 6个小时
  • 高性能

    • 数据中心网络 100G,时延约为几个 us
    • RDMA 网卡以及 programable switch 的应用
    • 我们想要的是: us 级别的共识,以及us级别的容错
    • HoverRaft
      • P4 programable switch: IP multicast
    • Mu
      • use one-sided RDMA
      • pull based heartbeat instead of push-based
  • 多节点提交(Leaderless)

    • 节点跨地域,导致节点间RTT(Round Trip Time)很大
    • EPaxos
      • 使用了冲突图的方式来允许并行Commit
      • 不冲突的情况下 1 RTT 提交时间

共识算法的未来

  • Raft Paxos 相互移植

    • Raft 有很多成熟的实现
    • 研究主要关注在 Paxos 上
    • 如何关联两种算法
      • On the Parallels between Paxos and Raft, and how to Port Optimizations
      • Paxos va Raft: Have we reached consensus on distributed consensus?
  • 共识算法作为一个系统

    • 多数分布式 系统都选择共识宣发作为底座
    • 不同一致性协议有不同的特性
    • Virtual consensus in delos
      • 对外暴露一致性的 LOG 作为接口
      • 内部对于 LOG 可以选择不同的实现