分布式与一致性协议之Raft算法与一致哈希算法(一)

2024-05-02 16:52

本文主要是介绍分布式与一致性协议之Raft算法与一致哈希算法(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Raft算法

Raft与一致性

有很多人把Raft算法当成一致性算法,其实它不是一致性算法而是共识算法,是一个Multi-Paxos算法,实现的是如何就一系列值达成共识。并且,Raft算法能容忍少数节点的故障。虽然Raft算法能实现强一致性,也就是线性一致性(Linearizability),但需要客户端协议的配合。在实际场景中,我们一般需要根据场景特点,在一致性强度和实现复杂度之间进行权衡。比如Consul实现了3种一致性模型。

  • 1.default:客户端访问领导者节点执行读操作,领导者确认自己处于稳定状态时(在leader leasing时间内),返回本地数据给客户端,否则返回错误给客户端。
    在这种情况下,客户端是可能读到旧数据的,比如此时发生了网络分区,新领导者已经更新过数据,但因为网络故障,旧领导者未更新数据也未退位,仍处于稳定状态。
  • 2.consistent:客户端访问领导者节点执行读操作,领导者在大多数节点确认自己仍是领导者之后返回本地数据给客户端,否则返回错误给客户端。在这种情况下,客户端读到的都是最新数据。
  • 3.stale:从任意节点读数据,不局限于领导者节点,客户端可能会读到旧数据。
    一般而言,在实际工程种,使用Consul的consistent旧可以了,不用线性一致性,只要能保证写操作完成后,每次读都能读到最新值即可。比如为了实现幂等操作,我们使用一个编号(ID)来唯一标记一个操作,并使用一个状态字段(nil/done)来标记操作是否已经执行,那么只要我们能保证设置了ID对应状态值为done后,能立即和一直读到最新状态值,旧可以防止操作的重复执行,实现幂等性。
  • 总的来说,Raft算法能很好地处理绝大部分场景地一致性问题,推荐在设计分布式系统时,优先考虑Raft算法,当Raft算法不能满足现有场景需求时,再去调研其他共识算法。比如QQ后台地海量分布式系统,其中配置中心、名字服务以及时序数据库地META节点,采用Raft算法。在设计时序数据库的DATA节点一致性时,基于水平扩展、性能和数据完整性等考虑,就没采用Raft算法,而是采用了Quorum NWR、失败重传、反熵等机制。这样安排的好处是,不仅满足了业务的需求,还通过尽可能采用最终一致性方案的方式,实现系统的高性能,降低了成本。

注意。
Raft算法和兰伯特的Mutli-Paxos的不同之处有两点:

  • 1.首先,在Raft算法中,不是所有节点都能当领导者,只有日志较完整地节点(也就是日志完整度不比半数节点低的节点)才能当选领导者
  • 2.其次,在Raft算法中,日志必须是连续的

思维拓展

Raft算法实现了"一切以我为准"的强领导者模型,那么这个设计有什么限制和局限呢?
领导者接收到大多数的"复制成功"响应后,就会将日志应用到自己的状态机,然后返回"成功"给客户端。如果此时有一个节点不在"大多数"中,也就是说它接收日志项失败,那么Raft算法会如何实现日志的一致呢?

对于接收日志项失败的节点,Raft算法采用了以下机制来确保日志的一致性:

  • 1.日志追赶(Log Compaction):如果某个节点因为某些原因(如网络分区、节点故障等)没有接收到最新的日志项,当该节点重新加入集群并成为跟随者后,它会向领导者请求复制缺失的日志项。领导者会将缺失的日志项发送给该节点,使其能够追赶上最新的日志状态。
  • 2.安全性检查:在复制缺失的日志项之前,领导者会首先检查该节点的日志是否与自己保持一致。如果发现不一致(例如该节点包含了一些领导者没有的日志项),领导者会拒绝复制请求,并告知该节点回滚到某个一致的日志位置后再重新请求复制。这样可以确保在复制过程中不会出现日志不一致的情况。
  • 3.安全性保证:Raft算法通过保证“已提交的日志项不会被覆盖或删除”来确保日志的一致性。具体来说,如果一条日志项已经被标记为已提交,那么领导者在后续的日志复制过程中,就不会再覆盖或删除这条已提交的日志项。即使领导者节点出现故障并被新的领导者替换,新的领导者也会继续复制和提交之前的已提交日志项,以确保所有节点的日志保持一致

重点总结

在了解了Raft算法的特点、领导者选举、什么是日志、如何复制日志以及如何处理不一致日志,还有成员变更的问题和单节点变更的方法等。希望大家能明确以下几个重点:

  • 1.本质上,Raft算法以领导者为中心,选举出的领导者以"一切以我为准"的方式,达成值的共识和实现各节点日志的一直。
  • 2.在Raft算法中,副本数据是以日志的形式存在的,其中日志项中的指令表示用户指定的数据。在Raft算法中日志必须是连续的,而兰伯特的Multi-Paxos不要求日志是连续的,而且在Raft算法中,日志不仅是数据的载体,日志的完整性还影响着领导者选举的结果。也就是说,日志完整性最高的节点才能当选领导者
  • 3.单节点变更是利用"一次变更一个节点,不会同时存在旧配置和新配置两个’大多数’"的特性,实现成员变更。

在了解完Raft算法后,有人可能会有这样的疑问:强领导者模型会限制集群的写性能,有什么办法能突破Raft集群的写性能瓶颈呢?可以通过一致哈希算法来实现分集群。

一致哈希算法

概述

有些人可能有这样的疑问:如果我们通过Raft算法实现了KV存储,虽然领导者模型简化了算法实现和共识协商,但写请求只能限制在领导者节点上处理,导致集群的接入性能约等于单机,随着业务发展,集群的性能可能就扛不住了,造成系统过载和服务不可用,这时该怎么办呢?
其实这是一个非常常见的问题。在我看来,这时我们就要通过分集群突破单集群的性能限制了。有人可能会说,分集群还不简单吗? 在模型中加入一个Proxyc层,由Proxy层处理来自客户端的读写请求,在接收到读写请求后,通过对Key做哈希找到对应的集群就可以了.
哈希算法的确是个办法,但它有个明显的缺点:当需要变更集群数时(比如从两个集群扩展为三个集群),大部分的数据都需要迁移,重新映射,而数据的迁移成本是非常高的,那么如何解决哈希算法数据迁移成本高的通电呢?答案就是使用一致哈希(Consistent Hashing)算法。
为了更好地理解如何通过哈希寻址实现KV存储地分集群,除了分析哈希算法寻址问题的本质之外,还会分析一致哈希是如何解决哈希算法数据迁移成本高这个痛点,以及如何实现数据访问的冷热相对均匀。你不仅能理解一致性哈希算法的原理,还能掌握通过一致哈希算法实现数访问冷热均匀的实战能力。

我们先来看一个思考题。
假设我们有一个由A、B、C3个节点组成(为了方便演示,使用节点来替代集群)的KV服务,每个节点存放不同的KV数据,如图所示
在这里插入图片描述

这篇关于分布式与一致性协议之Raft算法与一致哈希算法(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

HTTP 与 SpringBoot 参数提交与接收协议方式

《HTTP与SpringBoot参数提交与接收协议方式》HTTP参数提交方式包括URL查询、表单、JSON/XML、路径变量、头部、Cookie、GraphQL、WebSocket和SSE,依据... 目录HTTP 协议支持多种参数提交方式,主要取决于请求方法(Method)和内容类型(Content-Ty

Redis实现分布式锁全过程

《Redis实现分布式锁全过程》文章介绍Redis实现分布式锁的方法,包括使用SETNX和EXPIRE命令确保互斥性与防死锁,Redisson客户端提供的便捷接口,以及Redlock算法通过多节点共识... 目录Redis实现分布式锁1. 分布式锁的基本原理2. 使用 Redis 实现分布式锁2.1 获取锁

Redis分布式锁中Redission底层实现方式

《Redis分布式锁中Redission底层实现方式》Redission基于Redis原子操作和Lua脚本实现分布式锁,通过SETNX命令、看门狗续期、可重入机制及异常处理,确保锁的可靠性和一致性,是... 目录Redis分布式锁中Redission底层实现一、Redission分布式锁的基本使用二、Red

redis和redission分布式锁原理及区别说明

《redis和redission分布式锁原理及区别说明》文章对比了synchronized、乐观锁、Redis分布式锁及Redission锁的原理与区别,指出在集群环境下synchronized失效,... 目录Redis和redission分布式锁原理及区别1、有的同伴想到了synchronized关键字

Java对接MQTT协议的完整实现示例代码

《Java对接MQTT协议的完整实现示例代码》MQTT是一个基于客户端-服务器的消息发布/订阅传输协议,MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛,:本文主要介绍Ja... 目录前言前置依赖1. MQTT配置类代码解析1.1 MQTT客户端工厂1.2 MQTT消息订阅适配器1.

MySQL中处理数据的并发一致性的实现示例

《MySQL中处理数据的并发一致性的实现示例》在MySQL中处理数据的并发一致性是确保多个用户或应用程序同时访问和修改数据库时,不会导致数据冲突、数据丢失或数据不一致,MySQL通过事务和锁机制来管理... 目录一、事务(Transactions)1. 事务控制语句二、锁(Locks)1. 锁类型2. 锁粒