MIT6.824-Raft笔记:Raft初探、副本间log时序

news2024/12/25 1:38:44

从宏观角度说明raft在程序中的作用,和客户端的关系,以及多个副本之间的关系;从微观角度说明多个副本之间raft对日志处理的流程。 

1. Raft 初探

宏观角度说明raft在程序中的作用,和客户端的关系,以及多个副本之间的关系。

Raft会以库(Library)的形式存在于服务中。如果你有一个基于Raft的多副本服务,那么每个服务的副本将会由两部分组成:应用程序代码和Raft库,应用程序代码接收RPC或者其他客户端请求,不同节点的Raft库之间相互合作,来维护多副本之间的操作同步。从软件的角度来看一个Raft节点的上层,是应用程序代码。应用程序通常都有状态,Raft层会帮助应用程序将其状态拷贝到其他副本节点。例如:Key-Value数据库对应的状态就是Key-Value Table。应用程序往下,就是Raft层。Key-Value数据库需要对Raft层进行函数调用,来传递自己的状态和Raft反馈的信息。Raft本身也会保持状态,Raft的状态中,最重要的就是Raft会记录操作的日志。

对于一个拥有三个副本的系统来说,很明显我们会有三个服务器,这三个服务器有完全一样的结构(上面是应用程序层,下面是Raft层)。理想情况下,也会有完全相同的数据分别存在于两层(应用程序层和Raft层)中。除此之外,还有一些客户端,假设我们有了客户端1(C1),客户端2(C2)等等。客户端就是一些外部程序代码,它们想要使用服务,同时它们不知道,也没有必要知道,它们正在与一个多副本服务交互。从客户端的角度来看,这个服务与一个单点服务没有区别。

客户端会将请求发送给当前Raft集群中的Leader节点对应的应用程序。这里的请求就是应用程序级别的请求,例如一个访问Key-Value数据库的请求。这些请求可能是Put也可能是Get。Put请求带了一个Key和一个Value,将会更新Key-Value数据库中,Key对应的Value;而Get向当前服务请求某个Key对应的Value。看起来似乎没有Raft什么事,就像是普通的客户端服务端交互。一旦一个Put请求从客户端发送到了服务端,对于一个单节点的服务来说,应用程序会直接执行这个请求,更新Key-Value表,之后返回对于这个Put请求的响应。但是对于一个基于Raft的多副本服务,就要复杂一些。

假设客户端将请求发送给Raft的Leader节点,在服务端程序的内部,应用程序只会将来自客户端的请求对应的操作向下发送到Raft层,并且告知Raft层,请把这个操作提交到多副本的日志(Log)中,并在完成时通知我。之后Raft节点之间相互交互,直到过半的Raft节点将这个新的操作加入到它们的日志中,也就是说这个操作被过半的Raft节点复制了。当且仅当Raft的Leader节点知道了过半副本都有了这个操作的拷贝之后。Raft的Leader节点中的Raft层,会向上发送一个通知到应用程序,也就是Key-Value数据库,来说明:刚刚你提交给我的操作,我已经提交给过半副本,并且已经成功拷贝给它们了,现在你可以真正的执行这个操作了。

客户端发送请求给Key-Value数据库,这个请求不会立即被执行,当且仅当这个请求存在于过半的副本中时,Raft才会通知Leader节点,只有在这个时候,Leader才会实际的执行这个请求。对于Put请求来说,就是更新Value,对于Get请求来说,就是读取Value。最终,请求返回给客户端,这就是一个普通请求的处理过程。

为了严格保证Get请求的结果,可以也和写数据一样,走一遍raft log,但是也可以采用ReadIndex的方案;当然如果不需要特别严格,使用leaderRead即可。

学生提问:除了Leader节点,其他节点的应用程序层会有什么样的动作?

Robert教授:当一个操作最终在Leader节点被提交之后,每个副本节点的Raft层会将相同的操作提交到本地的应用程序层。在本地的应用程序层,会将这个操作更新到自己的状态。理想情况是所有的副本都将看到相同的操作序列,这些操作序列以相同的顺序出现在Raft到应用程序的upcall中,之后它们以相同的顺序被本地应用程序应用到本地的状态中。假设操作是确定的(比如一个随机数生成操作就不是确定的),所有副本节点的状态,最终将会是完全一样的。我们图中的Key-Value数据库,就是Raft论文中说的状态(也就是Key-Value数据库的多个副本最终会保持一致)。

2. Raft Log 同步时序

微观角度说明多个副本之间raft对日志处理的流程。

接下来我将画一个时序图来描述Raft内部的消息是如何工作的。假设我们有一个客户端,服务器1是当前Raft集群的Leader。同时,我们还有服务器2,服务器3。这张图的纵坐标是时间,越往下时间越长。假设客户端将请求发送给服务器1,这里的客户端请求就是一个简单的请求,例如一个Put请求。

服务器1的Raft层会发送一个添加日志(AppendEntries)的RPC到其他两个副本(S2,S3)。现在服务器1会一直等待其他副本节点的响应,一直等到过半节点的响应返回,这里的过半节点包括Leader自己。在一个只有3个副本节点的系统中,Leader只需要等待一个其他副本节点返回对于AppendEntries的正确响应。

两点说明:

  1. Server1的Execute可以理解为Apply步骤
  2. 如图所示,只等了日志复制完成的结果,这里需要leaderRead或者ReadIndex。

当Leader收到了过半服务器的正确响应,Leader会执行(来自客户端的)请求,得到结果,并将结果返回给客户端。

与此同时,服务器3可能也会将它的响应返回给Leader,尽管这个响应是有用的,但是这里不需要等待这个响应,这一点对于理解Raft论文中的图2是有用的。

在Raft中,没有明确的committed消息。相应的,committed消息被夹带在下一个AppendEntries消息中,由Leader下一次的AppendEntries对应的RPC发出。任何情况下,当有了committed消息时,这条消息会填在AppendEntries的RPC中。下一次Leader需要发送心跳,或者是收到了一个新的客户端请求,要将这个请求同步给其他副本时,Leader会将新的更大的commit号随着AppendEntries消息发出,当其他副本收到了这个消息,就知道之前的commit号已经被Leader提交,其他副本接下来也会执行相应的请求,更新本地的状态。

学生提问:S2和S3的状态怎么保持与S1同步?

Robert教授:现在Leader知道过半服务器已经添加了Log,可以执行客户端请求,并返回给客户端。但是服务器2还不知道这一点,服务器2只知道:我从Leader那收到了这个请求,但是我不知道这个请求是不是已经被Leader提交(committed)了,这取决于我的响应是否被Leader收到。服务器2只知道,它的响应提交给了网络,或许Leader没有收到这个响应,也就不会决定commit这个请求。这里还有一个阶段,一旦Leader发现请求被commit之后,它需要将这个消息通知给其他的副本,这里有一个额外的消息。

学生提问:这里的内部交互有点多吧?

Robert教授:是的,这是一个内部需要一些交互的协议,它不是特别的快。实际上,客户端发出请求,请求到达某个服务器,这个服务器至少需要与一个其他副本交互,在返回给客户端之前,需要等待多条消息。一个客户端响应的背后有多条消息的交互。

学生提问:也就是说commit信息是随着普通的AppendEntries消息发出的?那其他副本的状态更新就不是很及时了。

Robert教授:是的,作为实现者,这取决于你在什么时候将新的commit号发出。如果客户端请求很稀疏,那么Leader或许要发送一个心跳或者发送一条特殊的AppendEntries消息。如果客户端请求很频繁,那就无所谓了。因为如果每秒有1000个请求,那么下一条AppendEntries很快就会发出,你可以在下一条消息中带上新的commit号,而不用生成一条额外的消息。额外的消息代价还是有点高的,反正你要发送别的消息,可以把新的commit号带在别的消息里。实际上,我不认为其他副本(非Leader)执行客户端请求的时间很重要,因为没有人在等这个步骤。至少在不出错的时候,其他副本执行请求是个不太重要的步骤。例如说,客户端就没有等待其他副本执行请求,客户端只会等待Leader执行请求。其他副本在什么时候执行请求,不会影响客户端感受的请求时延。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1250884.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

激活函数与非线性化:探索神经网络中的关键元素

随着人工智能领域的迅猛发展,神经网络成为实现各种复杂任务的有力工具。其中,激活函数及其非线性化特性扮演着至关重要的角色。本文将深入探讨激活函数的基本概念、作用原理以及常见的几种激活函数,并介绍它们在神经网络中发挥的重要作用。 …

Web3 进入“殖民时代”

最近在 AI 和 Web3 领域发生了两件“大”事,两件事都具有指标意义,但在媒体上其意义都被大量的八卦细节给掩埋了。 其实看待任何重大事件,都可以有两种不同的视角。第一是娱乐的视角,在新闻事件中找乐子。如果是本着这个目的&…

STM32-使用固件库新建工程

参考链接: 【入门篇】11-新建工程—固件库版本(初学者必须认认真真看)_哔哩哔哩_bilibili 使用的MCU是STM32F103ZET6 。 这篇参考的是野火的资料,可以在“野火大学堂”或者它的论坛上下载。(我通常是野火和正点原子的资料混着看的…

【DDS】OpenDDS配置与使用

😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍OpenDDS配置与使用。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下次更…

能让PDF看起来像是扫描件的Look Scanned

什么是 Look Scanned ? Look Scanned 是一个能够让 PDF 看起来就像是扫描件一样的纯前端网站。你再也不需要麻烦地打印之后扫描了,你所需要的就是鼠标点几下。 这是个挺有意思的软件,但是老苏不确定什么场景下会用到这个软件,如果不想自己搭…

89. 打家劫舍【动态规划】

题目 题解 class Solution:def rob(self, nums: List[int]) -> int:N len(nums)# 定义状态: dp[i]表示从第i间房子开始抢劫,最多能抢到的金额dp [0 for i in range(N)]for i in range(N-1, -1, -1):if i N-1:dp[i] nums[i]elif i N-2:dp[i] max(nums[i], …

C语言—一维数组在内存中的存放

1、先看代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int arr[]{1,2,3,4,5,6,7,8,9,10}; int szsizeof(arr)/sizeof(arr[0]);int i0;for(i0;i<sz;i){printf("&arr[%d] %p\n",i,&arr[i]);}return 0; } 2、定…

【Mybatis】Mybatis操作数据库详解

Mybatis操作数据库 什么是MybatisMybatis入门准备工作创建Springboot工程 建表 创建实体类 配置数据库连接字符串编写持久层代码单元测试 Mybatis的基础操作打印日志参数传递增(insert)返回主键 删(delete)改(update)查(select) Mybatis XML配置文件配置连接字符串和Mybatis写持…

Jenkins CI/CD

1、 Jenkins CI/CD 流程图 说明&#xff1a;这张图稍微更形象一点&#xff0c;上线之前先把代码git到版本仓库&#xff0c;然后通过Jenkins 如Java项目通过maven去构建&#xff0c;这是在非容器之前&#xff0c;典型的自动化的一个版本上线流程。那它有哪些问题呢&#xff1f; …

Docker Swarm总结+基础、集群搭建维护、安全以及集群容灾(1/3)

博主介绍&#xff1a;Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 &#x1f345;文末获取源码下载地址&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb;…

基于C#实现外排序

一、N 路归并排序 1.1、概序 我们知道算法中有一种叫做分治思想&#xff0c;一个大问题我们可以采取分而治之&#xff0c;各个突破&#xff0c;当子问题解决了&#xff0c;大问题也就 KO 了&#xff0c;还有一点我们知道内排序的归并排序是采用二路归并的&#xff0c;因为分治…

【Redis基础】Redis安装及管理详细教程

✅作者简介&#xff1a;大家好&#xff0c;我是小杨 &#x1f4c3;个人主页&#xff1a;「小杨」的csdn博客 &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; 1&#xff0c;UBuntu安装Redis 1&#xff0c;使用su命令切换到root用户 su2&#xff0c;使用se…

windows运行Pangolin应用填坑心得——如何在window应用轻量级opengl软件Pangolin库显示3D界面及窗口

目录 0、前言1、最有效的安装打开方式准备工作安装git安装vcpkg&#xff08;1&#xff09;下载&#xff08;2&#xff09;安装&#xff08;3&#xff09;集成至vs 安装cmake 安装pangolin 2、应用实例c工程&#xff08;1&#xff09;vs创建新工程&#xff08;2&#xff09;新工…

盘点60个Python爬虫源码Python爱好者不容错过

盘点60个Python爬虫源码Python爱好者不容错过 爬虫&#xff08;Spider&#xff09; 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 链接&#xff1a;https://pan.baidu.com/s/1JWrDgl46_ammprQaJiKqaQ?pwd8888 提取码&#xff…

Mysql并发时常见的死锁及解决方法

使用数据库时&#xff0c;有时会出现死锁。对于实际应用来说&#xff0c;就是出现系统卡顿。 死锁是指两个或两个以上的事务在执行过程中&#xff0c;因争夺资源而造成的一种互相等待的现象。就是所谓的锁资源请求产生了回路现象&#xff0c;即死循环&#xff0c;此时称系统处于…

2023 年 认证杯 小美赛 国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 cs数模团队在认证杯 小美赛前为大家提供了许多资料的内容呀&am…

数字图像处理(实践篇)一 将图像中的指定目标用bBox框起来吧!

目录 一 实现方法 二 涉及的OpenCV函数 三 代码 四 效果图 一 实现方法 ①利用OTSU方法将前景与背景分割。 ②使用连通区域分析可以将具有相同像素值且位置相邻的前景像素点组成的图像区域识别。 ③画bbox。 ④显示结果。 二 涉及的OpenCV函数 ① OpenCV提供了cv2.th…

【小技巧】复制一个模块到你的工程(学习阶段很实用)

问题描述&#xff1a; 当我们学习Springboot时&#xff0c;需要创建大量的模块&#xff0c;而这些模块的许多代码都是重复的&#xff0c;只有模块名等相关的信息不一样&#xff0c;现在就教你如何快速创建一个模块。 应用场景&#xff1a; ①进入项目文件夹&#xff1a; ②复…

Android : 模仿西瓜视频_主页界面_简单应用

示例图&#xff1a; MainActivity.java package com.example.xihuashipingapp;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle; import android.util.DisplayMetrics; import android.view.View; import android.widget.Button; import android.…

计算机组成原理(计算机系统概述)

目录 一. 计算机的发展二. 计算机硬件的基本组成2.1 早期冯诺依曼机2.2 现代计算机的结构 三. 各硬件的工作原理3.1 主存储器的基本组成3.2 运算器的基本组成3.3 控制器的基本组成 四. 计算机的工作过程 \quad 一. 计算机的发展 计算机系统 硬件 软件 #mermaid-svg-gp2AsYELE…