深入浅出理解分布式一致性Paxos算法

简介: 深入浅出理解分布式一致性Paxos算法

概述


Paxos算法是Lamport宗师提出的一种基于消息传递的分布式一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一。本文的目的就是带领大家深入浅出理解Paxos算法,理解它的执行流程,然后通过一个例子来了解Paxos算法在分布式系统中起到的作用。如果有能力的同学可以直接拜读原文


分布式一致性

分布式系统通常由异步网络连接的多个节点构成,每个节点有独立的计算和存储。通常来说,分布式一致性一般指的式数据的一致性。比如分布式存储系统,通常以多副本冗余的方式实现数据的可靠存储。同一份数据的多个副本必须保证一致,而数据的多个副本又存储在不同的节点中,这里的分布式一致性问题就是存储在不同节点中的数据副本的取值必须一致。

如果不保证一致性,那么就说明这个系统中的数据根本不可信,数据也就没有意义,那么这个系统也就没有任何价值可言。

1671157971158.jpg

在分布式系统中,各个节点之间需要进行通信来保持数据的一致性,而通信的实现方式有共享内存和消息传递两种模型。基于消息传递通信模型的分布式系统,不可避免的会发生下面的错误:机器宕机,进程可能会慢、被杀死或者重启,消息可能会延迟、丢失、重复。那么在这种复杂的情况下该如何保证一致性呢?

而Paxos算法就是如何快速正确的在一个分布式系统中对某个数据的值达成一致,并且保证不论发生任何异常,都不会破坏整个系统的一致性。

注: 这里某个数据的值并不只是狭义上的某个数,它可以是一条日志,也可以是一条命令,根据应用场景不同,某个数据的值有不同的含义。


Paxos算法描述


Paxos算法的目标:在分布式环境下确定一个值,这个值被所有节点承认。


角色


Paxos将系统中的角色分为提议者 (Proposer),决策者 (Acceptor),和最终决策学习者 (Learner):

  • Proposer: 提出提案 (Proposal)。Proposal信息包括提案编号 (Proposal ID) 和提议的值 (Value)。
  • Acceptor: 参与决策,回应Proposers的提案。收到Proposal后可以接受提案,若Proposal获得多数

Acceptors的接受,则称该Proposal被批准。

  • Learner: 不参与决策,从Proposers/Acceptors学习最新达成一致的提案(Value)。

在具体的实现中,一个进程可能同时充当多种角色。比如一个进程可能既是Proposer又是Acceptor又是Learner。


算法流程

1671157992838.jpg

Propser有两个重要属性,提案编号N, 提案V, 简记 Proposer(N, V)。

Acceptor有三个重要属性,响应提案编号ResN, 接受的提案编号AcceptN, 接收的提案AcceptV, 间记Acceptor(ResN, AcceptN, AcceptV)。

第一阶段: Prepare准备阶段

Proposer: Proposer生成全局唯一且递增的提案编号N,,向所有Acceptor发送Prepare请求,这里无需携带提案内容,只携带提案编号即可, 即发送 Proposer(N, null)。

Acceptor: Acceptor收到Prepare请求后,有两种情况:

  1. 如果Acceptor首次接收Prepare请求, 设置ResN=N, 同时响应ok
  2. 如果Acceptor不是首次接收Prepare请求,则:
  • 若请求过来的提案编号N小于等于上次持久化的提案编号ResN,则不响应或者响应error。
  • 若请求过来的提案编号N大于上次持久化的提案编号ResN, 则更新ResN=N,同时给出响应。响应的结果有两种,如果这个Acceptor此前没有接受过提案, 只返回ok。否则如果这个Acceptor此前接收过提案,则返回ok和上次接受的提案编号AcceptN, 接收的提案AcceptV。

第二阶段: Accept接受阶段

Proposer: Proposer收到响应后,有两种情况:

  1. 如果收到了超过半数响应ok, 检查响应中是否有提案,如果有的话,取提案V=响应中最大AcceptN对应的AcceptV,如果没有的话,V则有当前Proposer自己设定。最后发出accept请求,这个请求中携带提案V。
  2. 如果没有收到超过半数响应ok, 则重新生成提案编号N, 重新回到第一阶段,发起Prepare请求。

Acceptor: Acceptor收到accept请求后,分为两种情况:

  1. 如果发送的提案请求N大于此前保存的RespN,接受提案,设置AcceptN = N, AcceptV=V, 并且回复ok。
  2. 如果发送的提案请求N小于等于此前保存的RespN,不接受,不回复或者回复error。

Proposer: Proposer收到ok超过半数,则V被选定,否则重新发起Prepare请求。

第三阶段: Learn学习阶段

Learner: Proposer收到多数Acceptor的Accept后,决议形成,将形成的决议发送给所有Learner。

1671158000516.jpg


Paxos应用案例


前面讲述了paxos算法细节,可能你还是不明白paxos算法在实际场景中有什么用处,我们现在讲个实际的使用案例。

我们以一个分布式的KV数据库为例,分析Paxos的应用场景。

1671158008252.jpg

3个server组成一个分布式内存数据库,他们的状态必须保持同步,也就是每个server 节点都需要维护有顺序的操作日志,同时保持一致。

+---+-------------+
|1  |Put("a", 1)  |
+---+-------------+
|2  |Put("b", 2)  |
+---+-------------+
|3  |Put("c", 3)  |
+---+-------------+

多个客户端并发在发送请求的时候,服务端多个节点需要协商,选择其中一个大家都认可的数据(指令), 存入到操作表中,这里协商确定指令的过程就是Paxos

比如我们将paxos算法封装到下面的方法中:

Op doPaxos(int seq, Op v){...}

以上面图示的例子详细分下这个过程:

  1. Cient2向集群发送了请求Put("b", 2),假设这个请求最终到了server1上。
  2. Client3向集群发送了请求Put("c", 3), 假设这个求情发到了server2上。
  3. server2调用doPaxos函数进行协商,即询问集群中的所有server咱们的第2个操作能否为Put("c", 2)
  4. 此时server3也调用doPaxos函数进行协商,即询问集群中的所有server咱们的第2个操作能否为Put("c", 3)
  5. 这是Paxos只会选择其中1个提案,我们这里假设server2的议题最终被通过了,集群中所有server的状态表都新增Put("c", 2)
  6. server3发现自己的提案没有选中,他会对自己的database进行Put("b", 2)操作,然后重新升级提案编号,再次调用doPaxos方法,直到自己的提案被通过。


总结


Paxos算法还是挺难以理解的,如果对整个推导过程感兴趣的话,可以阅读Lamport的原文,或者阅读这篇文章,也写的特别好。

根据前面讲述的Paxos算法流程,不知道大家有没有发现一个问题,如果两个Propser依次提出编号递增的提案,最终回陷入死循环,进入死锁状态,如下图:

1671158023359.jpg

我们可以通过选取主Proposer,就可以保证Paxos算法的活性, 这样是ZAB协议的由来。

目录
相关文章
|
4月前
|
算法 Go
[go 面试] 雪花算法与分布式ID生成
[go 面试] 雪花算法与分布式ID生成
|
16天前
|
算法 关系型数据库 MySQL
分布式唯一ID生成:深入理解Snowflake算法在Go中的实现
在分布式系统中,确保每个节点生成的 ID 唯一且高效至关重要。Snowflake 算法由 Twitter 开发,通过 64 位 long 型数字生成全局唯一 ID,包括 1 位标识位、41 位时间戳、10 位机器 ID 和 12 位序列号。该算法具备全局唯一性、递增性、高可用性和高性能,适用于高并发场景,如电商促销时的大量订单生成。本文介绍了使用 Go 语言的 `bwmarrin/snowflake` 和 `sony/sonyflake` 库实现 Snowflake 算法的方法。
27 1
分布式唯一ID生成:深入理解Snowflake算法在Go中的实现
|
28天前
|
存储 缓存 算法
分布式缓存有哪些常用的数据分片算法?
【10月更文挑战第25天】在实际应用中,需要根据具体的业务需求、数据特征以及系统的可扩展性要求等因素综合考虑,选择合适的数据分片算法,以实现分布式缓存的高效运行和数据的合理分布。
|
28天前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
2月前
|
算法
基于粒子群算法的分布式电源配电网重构优化matlab仿真
本研究利用粒子群算法(PSO)优化分布式电源配电网重构,通过Matlab仿真验证优化效果,对比重构前后的节点电压、网损、负荷均衡度、电压偏离及线路传输功率,并记录开关状态变化。PSO算法通过迭代更新粒子位置寻找最优解,旨在最小化网络损耗并提升供电可靠性。仿真结果显示优化后各项指标均有显著改善。
|
2月前
|
消息中间件 缓存 算法
分布式系列第一弹:分布式一致性!
分布式系列第一弹:分布式一致性!
|
2月前
|
算法 Java 关系型数据库
漫谈分布式数据复制和一致性!
漫谈分布式数据复制和一致性!
|
4月前
|
Oracle 关系型数据库
分布式锁设计问题之Oracle RAC保证多个节点写入内存Page的一致性如何解决
分布式锁设计问题之Oracle RAC保证多个节点写入内存Page的一致性如何解决
|
4月前
|
消息中间件 存储 监控
消息队列在分布式系统中如何保证数据的一致性和顺序?
消息队列在分布式系统中如何保证数据的一致性和顺序?
|
4月前
|
消息中间件 存储 C#
分布式事务之最终一致性实现方案
分布式事务之最终一致性实现方案
83 0