探索分布式强一致性奥秘:Paxos共识算法的精妙之旅

2024-02-22 15:52

本文主要是介绍探索分布式强一致性奥秘:Paxos共识算法的精妙之旅,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        提到分布式算法,就不得不提 Paxos 算法,在过去几十年里,它基本上是分布式共识的代名词,因为当前一批常用的共识算法都是基于它改进的。比如,Fast Paxos 算法、Cheap Paxos、Raft 算法等。

        由莱斯利·兰伯特(Leslie Lamport)于1990年首次提出,并在后续文章中进一步阐述。Paxos 算法旨在解决在一个可能发生网络分区、节点失效或其他异常情况的分布式环境中,如何让所有参与决策的节点对某个值达成一致同意的问题。

        兰伯特提出的Paxos总共包含两部分:

  1. 一个是 Basic Paxos 算法,描述的是多节点之间如何就某个值(提案Value)达成共识
  2. 另一个是 Multi-Paxos 思想,描述的是执行多个 Basic Paxos 实例,就一系列值达成共识

Basic Paxos

        先来看一个例子

        假设有一个分布式集群,由三个节点 A、B、C 组成,提供只读 KV 存储服务,创建只读变量的时候,必须要先写入数据,而且这个数据后续不能被修改。因此一个节点写入只读变量后就不能再修改了,所以所有节点必须要先对只读变量达成共识,然后所有节点在一次创建这个只读变量。

        当有多个客户端(如客户端1、2)访问这个系统试图创建同一个只读变量(如X),客户端1试图创建值为3的X,客户端2试图创建值为7的X,这样要如何达成共识,实现各节点上X值一直呢?

        为了帮助人们更好的理解 Basic Paxos 算法,兰伯特在讲解时,也使用了一些独有而且比较重要的概念,提案、准备(Prepare)请求、接受(Accept)请求、角色等等,其中最重要的就是角色。因为角色是对 Basic Paxos 中最核心的三个功能的抽象,比如,由接受者(Acceptor)对提议者的值进行投票,并存储接受的值。

        角色划分

        在 Basic Paxos 中,由提议者(Proposer)、接受者(Acceotor)、学习者(Learner)三种角色,如图:

  • 提议者(Proposer):提议一个值,用于投票表决。为了方便演示,可以把客户端1和2看做是提议者。但在绝大多数场景中,集群中收到客户端请求的节点,才是提议者。这样做的好处是,对业务代码没有侵入性,也就是说,我们不需要在代码中实现算法逻辑,就可以像使用数据库一样访问后端数据。
  • 接受者(Acceptor):对每个提议的值进行投票,并存储接受的值,比如 A、B、C 三个节点。一般来说,集群中的所有节点都在扮演接受者的角色,参与共识协商,并接受和存储数据。

        这里需要强调一下:前面不是说接收客户端请求的节点是提议者吗?这里怎么又是接受者呢?这是因为一个节点(或进程)可以身兼多个角色。想象一下,一个 3 节点的集群,1 个节点收到了请求,那么该节点将作为提议者发起二阶段提交,然后这个节点和另外 2 个节点一起作为接受者进行共识协商,就像下图的样子:

  • 学习者(Leaner):被告知投票的结果,接受达成的共识值,存储保存,不参与投票的过程。一般来说,学习者是备份节点,比如“Master-Slave”模型中的Slave,被动的接受数据,容灾备份。

        达成共识过程

        有这样一个场景,假如你所在的公司有一个新项目需要开发,业务比较复杂,你的领导给组内每个成员下发了任务,要求每人写一个项目方案,最终开会讨论采用哪套方案,为了区分每套方案,每个方案都有一个标识,称为提案编号,来唯一标识。

        与你的做法类似,在 Basic Paxos 中,兰伯特也使用提案代表一个提议。不过在提案中,除了提案编号,还包含了提议值。使用 [n, v] 表示一个提案,n 为提案编号,v 为提议值。

        整个共识协商是分两个阶段进行的。假设客户端 1 的提案编号为 1,客户端 2 的提案编号为5,并假设节点 A、B 先收到来自客户端1的准备请求,节点 C 先收到来自客户端 2 的准备请求。

        准备(Prepare)阶段

        先来看第一阶段,首先客户端 1、2 作为提议者,分别向所有接受者发送包含提案编号的准备请求:

        在准备请求时不需要准备提议的值的,只需要携带提案编号就可以了,这是容易误解的地方。接着,当A、B收到提案编号为 1 的准备请求,节点 C 收到提案编号为 2 的准备请求后,将进行这样的处理:

  • 由于之前没有通过任何提案,所以节点 A、B 将返回一个"尚无提案"的响应。也就说节点 A和 B 在告诉提议者,我之前没有通过任何提案,并承诺以后不在响应提案编号小于等于 1 的准备请求,不会通过编号小于1的提案。
  • 节点 C 也是如此,它将返回一个“尚无提案”的响应,并承诺以后不在响应提案编号小于 5 的提案,不会通过提案编号小于5的提案。

        另外,当节点 A、B 收到提案编号为 5 的准备请求,和节点 C 收到提案编号为 1 的准备请求的时候,将进行这样的处理:

  • 当节点 A、B 收到提案编号为 5 的准备请求时,因为提案编号 5 大于他们之前响应的准备请求的提案编号 1,而且两个节点都没有通过任何提案,所以它将返回一个“尚无提案”的响应,并承诺以后不在响应提案编号小于 5 的准备请求,不会通过提案小于 5 的提案。
  • 当节点 C 收到提案编号为 1 的准备请求时,由于天编号 1 小于之前响应的准备请求的提案编号 5,所以丢弃该准备请求,不做响应。

        接受(Acceptor)阶段

        第二个阶段也就是接受阶段,首先客户端 1、2 在收到大多数节点的准备响应之后,会分别发送接受请求:

  • 当客户端 1 收到大多数的接受者(节点A、B)的准备响应之后根据响应中提案编号最大的提案值,设置接受请求中的值。因为该值在来自节点 A、B 的准备响应中都为空,所以就把自己的提议值 3 作为提案的值,发送接受请求 [1, 3]。
  • 当客户端2收到大多数的接受者的准备响应后(节点A、B、C),根据响应中提案编号最大的提案值,来设置接受请求中的值。因为该值来自节点 A、B、C 准备响应都为空,所以就把自己的提议值7作为提案的值,发送接受请求 [5, 7]。

        当三个节点接受到两个客户端的接受请求时,会进行这样的处理:

  • 当节点 A、B、C 接受到请求 [1, 3] 的时候,由于提案的提案编号 1 小于三个节点承诺能通过的提案的最小提案编号 5,所以提案 [1, 3] 将被拒绝。
  • 当节点 A、B、C 接受到请求 [5, 7] 的时候,由于提案的提案编号 5 不小于三个节点承诺能通过的提案的最小提案编号 5,所以就通过提案 [5, 7],也就是接受了值 7,三个节点就 X 值为 7 达成共识。

        如果集群中有学习者,当接受者通过了一个提案时,就通知给所有的学习者。当学习者发现大多数的接受者都通过了某个提案,那么它也通过该提案,接受该提案的值。  

Multi-Paxos算法 

        Basic Paxos 只能就单个值(Value)达成共识,一旦遇到为一系列的值实现共识的时候,它就不管用了。虽然兰伯特提到可以通过多次执行 Basic Paxos 实例(比如每接收到一个值时,就执行一次 Basic Paxos 算法)实现一系列值的共识。但是,读完论文后,虽然每个英文单词都能读懂,但还是不理解兰伯特提到的 Multi-Paxos,为什么 Multi-Paxos 这么难理解呢?

        兰伯特并没有把 Multi-Paxos 讲清楚,只是介绍了大概的思想,缺少算法过程的细节和编程所必须的细节。这就导致了每个人实现的 Multi-Paxos 都不一样。不过从本质上看,大家都是在兰伯特提到的 Multi-Paxos 思想上补充细节,设计自己的 Multi-Paxos 算法,然后实现它(比如 Chubby 的 Multi-Paxos 实现、Raft 算法等)。

        所以这里补充一下,兰伯特提出的 Multi-Paxos 是一种思想,不是算法。而 Multi-Paxos 是一种统称,它是指基于 Multi-Paxos 思想,通过多个 basic-Paxos 实现一系列值的共识算法。这一点尤为重要。

        到这里 Paxos 共识算法就介绍完了。

这篇关于探索分布式强一致性奥秘:Paxos共识算法的精妙之旅的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/735746

相关文章

Jenkins分布式集群配置方式

《Jenkins分布式集群配置方式》:本文主要介绍Jenkins分布式集群配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.安装jenkins2.配置集群总结Jenkins是一个开源项目,它提供了一个容易使用的持续集成系统,并且提供了大量的plugin满

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

浅析如何保证MySQL与Redis数据一致性

《浅析如何保证MySQL与Redis数据一致性》在互联网应用中,MySQL作为持久化存储引擎,Redis作为高性能缓存层,两者的组合能有效提升系统性能,下面我们来看看如何保证两者的数据一致性吧... 目录一、数据不一致性的根源1.1 典型不一致场景1.2 关键矛盾点二、一致性保障策略2.1 基础策略:更新数

Golang实现Redis分布式锁(Lua脚本+可重入+自动续期)

《Golang实现Redis分布式锁(Lua脚本+可重入+自动续期)》本文主要介绍了Golang分布式锁实现,采用Redis+Lua脚本确保原子性,持可重入和自动续期,用于防止超卖及重复下单,具有一定... 目录1 概念应用场景分布式锁必备特性2 思路分析宕机与过期防止误删keyLua保证原子性可重入锁自动

基于MongoDB实现文件的分布式存储

《基于MongoDB实现文件的分布式存储》分布式文件存储的方案有很多,今天分享一个基于mongodb数据库来实现文件的存储,mongodb支持分布式部署,以此来实现文件的分布式存储,需要的朋友可以参考... 目录一、引言二、GridFS 原理剖析三、Spring Boot 集成 GridFS3.1 添加依赖

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Redis中的数据一致性问题以及解决方案

《Redis中的数据一致性问题以及解决方案》:本文主要介绍Redis中的数据一致性问题以及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Redis 数据一致性问题的产生1. 单节点环境的一致性问题2. 网络分区和宕机3. 并发写入导致的脏数据4. 持

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

Redis实现分布式锁全解析之从原理到实践过程

《Redis实现分布式锁全解析之从原理到实践过程》:本文主要介绍Redis实现分布式锁全解析之从原理到实践过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、背景介绍二、解决方案(一)使用 SETNX 命令(二)设置锁的过期时间(三)解决锁的误删问题(四)Re

Gradle下如何搭建SpringCloud分布式环境

《Gradle下如何搭建SpringCloud分布式环境》:本文主要介绍Gradle下如何搭建SpringCloud分布式环境问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录Gradle下搭建SpringCloud分布式环境1.idea配置好gradle2.创建一个空的gr