图解 Raft 共识算法:如何复制日志?

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 上次讲到 Raft 领导者选举:「图解 Raft 共识算法:如何选举领导者?」,接着这个话题继续跟大家聊下关于 Raft 日志复制的一些细节。

上次讲到 Raft 领导者选举:「图解 Raft 共识算法:如何选举领导者?」,接着这个话题继续跟大家聊下关于 Raft  日志复制的一些细节。


Raft 日志格式



在 Raft 算法中,需要实现分布式一致性的数据被称作日志,我们 Java 后端绝大部分人谈到日志,一般会联想到项目通过 log4j 等日志框架输出的信息,而 Raft 算法中的数据提交记录,他们会按照时间顺序进行追加,Raft 也是严格按照时间顺序并已一定的格式写入日志文件中:


640.png

如上图所示,Raft 的日志以日志项(LogEntry)的形式来组织,每个日志项包含一条命令、任期信息、日志项在日志中的位置信息(索引值 LogIndex)。


  • 指令:由客户端请求发送的执行指令,有点绕口,我觉得理解成客户端需要存储的日志数据即可。
  • 索引值:日志项在日志中的位置,需要注意索引值是一个连续并且单调递增的整数。
  • 任期编号:创建这条日志项的领导者的任期编号。


日志复制过程



Raft 的复制过程大致如下:


领导者接收到客户端发来的请求,创建一个新的日志项,并将其追加到本地日志中,接着领导者通过追加条目 RPC 请求,将新的日志项复制到跟随者的本地日志中,当领导者收到大多数跟随者的成功响应之后,则将这条日志项应用到状态机中,可以理解成该条日志写成功了,最后领导者返回日志写成功的消息响应客户端,流程如下图所示:

640.png

可以看出,Raft 的复制过程中,领导者接收到大多数跟随者成功响应,并且将日志项应用到状态机之后,不需要将结果响应给跟随者,而是直接将成功消息响应给客户端,这是一种优化方式,同时 Raft 会在下一次 RPC 追加日志请求中附加上本次的日志项信息。


以上仅仅只是一种没有发生任何问题的复制过程,在这过程中难免会发生节点宕机等问题,在这种情况下,Raft 是如何处理的呢?


如何保证日志的一致性?



上面讲到,在正常情况下,领导者的日志追加 RPC 请求响应都成功的情况下,领导人和跟随者的日志保持一致性。然而在领导者突然宕机的情况下有可能会造成领导者与跟随者日志不一致的情况,这种情况会随着后续领导者一些列宕机的情况下加剧问题的严重:

640.png


注:例子来源于 Raft 论文。


如上所示,当一个领导者成功当选时,跟随者有可能是 a-f 的情况:


  1. a-b 表示跟随者的日志项落后于当前领导者;
  2. c-d 表示跟随者有些日志项没有被提交;
  3. e-f 情况稍微有点复杂,以上两种情况它们都存在。


下面我来还原上面图所表示的情况是怎么发生的:


假设一开始 e 为领导者,在任期 2 时,f 被推选为领导者,写入了若干日志项之后,在追加 RPC 请求中崩溃了,重启后又被选举为领导者(任期号 3),又在写入了若干日志项之后奔溃了;e 此时又重新选举为领导者(任期号为 4),成功复制了若干日志项,同时还有一部分没有成功追加到大多数跟随者又崩溃了,同时跟随者 b 复制了一部分日志项之后崩溃了;假设 a 在任期 5 时被选举为领导者,c 在任期 6 时被选举为领导者,还未全部将本地日志复制到其他跟随者之前又崩溃了,在任期 7 时 d 被选择为领导者,写入了若干日志项之后,在追加 RPC 请求中崩溃了,最后形成了上图的情况。


面对以上的情况,Raft 是如何解决日志的一致性呢?


在 Raft 的日志机制中,为了简化日志一致性的行为,有以下两点非常重要的特性:


  1. 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们存储了相同的指令。
  2. 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们之前的所有日志条目也全部相同。


第一个特性是因为 Raft 日志项在日志中不会改变,因此只要日志项只要是索引值和任期号相同,就可以认为他们是存储了相同的指令数据信息。


第二个特性是因为领导者会通过强制覆盖的方式让跟随者复制自己的日志来解决日志不一致的问题,领导者在追加 RPC 请求过程中会附带需要复制的日志以及前一个日志项相关信息,如果跟随者匹配不到包含相同索引位置和任期号的日志项,那么他就会拒绝接收新的日志条目,接着领导者会继续递减要复制的日志项索引值,直至找到相同索引和任期号的日志项,最后就直接覆盖跟随者之后的日志项。可认为两个条目拥有相同的索引和任期号,那么他们之前的所有日志条目也全部相同。


因此,Raft 的日志追加大致可分为两个步骤:

  1. 领导者找到跟随者与自己相同的最大日志项,这意味着跟随者之前的日志都与领导者的日志相同;
  2. 领导者强制覆盖之后不一致的日志,实现日志的一致性。


下面我用一个例子充分表达 Raft 在日志复制过程中是如何进行日志强制覆盖的。

假设有一个领导者和一个跟随者,他们的日志项复制情况如下:


640.png

可以看出,跟随者在任期号 3 时是领导者,在追加日志过程中崩溃了,重启之后成为跟随者,随后新的领导者向其追加日志,此时他的任期号为 3 最后的一个日志项将被覆盖。


先来看下 Raft 追加条目 RPC 的请求参数:

参数 描述
term 领导者的任期
leaderId 领导者ID 因此跟随者可以对客户端进行重定向(译者注:跟随者根据领导者id把客户端的请求重定向到领导者,比如有时客户端把请求发给了跟随者而不是领导者)
prevLogIndex 紧邻新日志条目之前的那个日志条目的索引
prevLogTerm 紧邻新日志条目之前的那个日志条目的任期
entries[] 需要被保存的日志条目(被当做心跳使用是 则日志条目内容为空;为了提高效率可能一次性发送多个)
leaderCommit 领导者的已知已提交的最高的日志条目的索引


领导者追加并覆盖跟随者过程如下:

640.png

  1. 领导者通过日志追加 RPC 请求,将当前最新的要追加到跟随者的日志项以及前一个它的 prevLogIndex=7、prevLogTerm=3 等信息发送跟跟随者;
  2. 跟随者判断当前最新的日志的任期号与 prevLogTerm 不一致,拒绝追加;
  3. 领导者继续递减需要复制的日志项的索引值,此时 prevLogIndex=6、prevLogTerm=3;
  4. 跟随者找到了 LogIndex=6、LogTerm=3 的日志项,跟随者接受追加请求;
  5. 领导者接着会将跟随者  LogIndex=6、LogTerm=3 的日志项之后的日志项进行追加并覆盖。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
9天前
|
存储 算法 安全
分布式系统架构1:共识算法Paxos
本文介绍了分布式系统中实现数据一致性的重要算法——Paxos及其改进版Multi Paxos。Paxos算法由Leslie Lamport提出,旨在解决分布式环境下的共识问题,通过提案节点、决策节点和记录节点的协作,确保数据在多台机器间的一致性和可用性。Multi Paxos通过引入主节点选举机制,优化了基本Paxos的效率,减少了网络通信次数,提高了系统的性能和可靠性。文中还简要讨论了数据复制的安全性和一致性保障措施。
26 1
|
2月前
|
算法
raft算法的自我理解
本文介绍了Raft算法的基本概念和工作原理,包括它如何通过日志复制和领导选举来实现分布式系统中不同机器的强一致性。
33 2
|
5月前
|
算法
Bully、Raft、Zab选举算法的差异比较
Bully算法、Raft算法、Zab的差与异。他们如何脱胎于Paxos而成?
|
4月前
|
存储 算法 NoSQL
(七)漫谈分布式之一致性算法下篇:一文从根上儿理解大名鼎鼎的Raft共识算法!
Raft通过一致性检查,能在一定程度上保证集群的一致性,但无法保证所有情况下的一致性,毕竟分布式系统各种故障层出不穷,如何在有可能发生各类故障的分布式系统保证集群一致性,这才是Raft等一致性算法要真正解决的问题。
122 11
|
4月前
|
存储 算法 索引
(六)漫谈分布式之一致性算法上篇:用二十六张图一探Raft共识算法奥妙之处!
现如今,大多数分布式存储系统都投向了Raft算法的怀抱,而本文就来聊聊大名鼎鼎的Raft算法/协议!
131 8
|
4月前
|
算法 关系型数据库 程序员
第一周算法设计与分析:A : log2(N)
这篇文章介绍了解决算法问题"输入一个数N,输出log2N(向下取整)"的三种编程思路,包括使用对数函数和幂函数的转换方法,以及避免浮点数精度问题的整数逼近方法。
|
1月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
263 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
5天前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
|
2月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
292 3
|
15天前
|
存储 监控 安全
什么是事件日志管理系统?事件日志管理系统有哪些用处?
事件日志管理系统是IT安全的重要工具,用于集中收集、分析和解释来自组织IT基础设施各组件的事件日志,如防火墙、路由器、交换机等,帮助提升网络安全、实现主动威胁检测和促进合规性。系统支持多种日志类型,包括Windows事件日志、Syslog日志和应用程序日志,通过实时监测、告警及可视化分析,为企业提供强大的安全保障。然而,实施过程中也面临数据量大、日志管理和分析复杂等挑战。EventLog Analyzer作为一款高效工具,不仅提供实时监测与告警、可视化分析和报告功能,还支持多种合规性报告,帮助企业克服挑战,提升网络安全水平。