首页 > 编程语言 >raft算法和etcd代码解析-4.两个模块,两个goroutine

raft算法和etcd代码解析-4.两个模块,两个goroutine

时间:2024-04-06 09:12:27浏览次数:23  
标签:uint64 etcd goroutine MessageType 状态机 模块 raft 日志 节点

etcd是什么

存储:Kubernetes集群所有的配置信息和状态数据都会被持久化存储在etcd中,包括节点信息、Pods、ReplicaSets、Services、ConfigMaps、Secrets等各类资源对象。

协调:通过Raft协议,etcd集群中的各个节点达成一致,确保任何时候集群状态的变更都是原子性的、一致的,并且在节点故障时能够快速恢复。

调度:Kubernetes的控制面组件正是通过与etcd交互来管理整个集群的运行状态,例如,当用户通过API Server创建或修改资源时,这些更改首先会被记录到etcd中,然后由controller manager和scheduler等组件根据etcd中的数据来执行相应的集群操作。

模块

算法层(SDK) ./raft/*
应用层(示例) ./contrib/raftexample/*
数据结构定义 ./raftraftp

ectd关键词

etcd是一个强一致性的分布式键值对存储系统,底层基于raft协议保证分布式的一致性和可用性

algorithm module/算法模块
内聚了raft共识机制核心模块,代码层以sdk形式被应用层引入,启动时以独立的goroutine存在,与应用模块通过channel异步通信,决定了应用模块什么时候做以及该做什么

application module/应用模块
聚合了etcd存储通信能力模块,启动时是raft节点的主goruntine,负责与客户通信,与算法模块交互,与算法模块通过channel异步通信等职责

node/算法节点
raft节点在算法层的抽象也是应用层与算法层的交互入口

raft node/应用节点
是raft节点在应用层的抽象,内部拥有node,同时提供客户端请求,以及与集群其他节点通信的能力

transport/网络模块
etcd中的网络模块,为raft节点集群内部通信提供服务,应用层引入,独立于算法模块

proposal/提议
两阶段提交中的第一阶段

commit/提交
两阶段中的第二阶段

apply/应用
将已经提交的日志应用到数据状态机,使得写请求生效

data state machine/数据状态机
raft节点用于存储数据的机制,是KV数据库

node state machine/节点状态机
etcd实现中raft节点本质是一个大的状态机,任何操作,例如选举,数据的提交,都会封装成消息输入节点状态机,驱动节点状态发生变化

graph LR A(algorithm)<---->B(application) B-->C(预写日志持久化) B-->D(维护数据状态机) B-->E(节点通信)

两个channel

应用模块和算法模块是两个互相阻塞监听的channel

graph LR A(Application)--reciveC-->B(Algorithm) A--propC-->B B--readyC-->A A--advanceC-->B A--tickC-->B

模块通信每个轮次是有来有回的,例如一次日志处理就包括了prop ready advance的多通道(Channel)间通信

应用模块通道职责
接收响应客户端请求
预写日志持久化
raft节点通信
维护数据状态机

算法模块通道职责
日志两阶段提交
节点角色管理
选举投票决策
竞选计时
心跳计时

[!quote]
./contrib/raftexample/raft.go中serveChannels函数中的阻塞监听例子如下

for rc.proposeC != nil && rc.confChangeC != nil {
	select {
	case prop, ok := <-rc.proposeC:
		if !ok {
			rc.proposeC = nil
		} else {
			// blocks until accepted by raft state machine
			rc.node.Propose(context.TODO(), []byte(prop))
		}

	case cc, ok := <-rc.confChangeC:
		if !ok {
			rc.confChangeC = nil
		} else {
			confChangeCount += 1
			cc.ID = confChangeCount
			rc.node.ProposeConfChange(context.TODO(), cc)
		}
	}
}

预写日志EntryType

EntryType是算法模块的一个类型
EntryType就是包含预写日志内容的数据,又被Message类型包含
注意此处包括之后的代码并不完全复原etcd中的源代码,而是抽象的表示

type EntryType int32

const (
    //普通日志内容数据
	EntryNormal     EntryType = 0
	//改变配置的数据
	EntryConfChange EntryType = 1
)

//...中略

type Entry struct {
    //任期
	Term             uint64
	//索引
	Index            uint64
	Type             EntryType
	//数据内容
	Data             []byte
}

Message类型

Message就是节点之间传递的信息,前面提到,两个通道的消息是包含多种内容,因此通信的Message的类型是多种的,Message结构体包含的成员数据也是冗余的。

MessageType类型

type MessageType int32

const (
	MsgHup            MessageType = 0 //通知Leader心跳消失,之后节点会推举自己为leader
	MsgBeat           MessageType = 1 //Leader心跳
	MsgProp           MessageType = 2 //已接受到客户端写请求
	MsgApp            MessageType = 3 //Leader向集群其他节点同步数据
	MsgAppResp        MessageType = 4 //(该节点是Leader) 发出的MsgApp请求得到响应
	MsgVote           MessageType = 5 //投票请求
	MsgVoteResp       MessageType = 6 //投票请求响应
//...
	MsgHeartByte      MessageType = 8 //leader发送心跳
	MsgHeartByteResp  MessageType = 9 //follower心跳响应
//...
	MsgReadIndex      MessageType = 15 //客户端读请求
	MsgReadIndexResp  MessageType = 16 //客户端读请求响应、
	MsgPreVote        MessageType = 17 /*见详解(1)*/
	MsgPreVoteResp    MessageType = 18 /*见详解(1)*/
)
  1. MsgPreVote为预选举,是为了解决在一个分布式系统中,不同的节点之间由于网络故障或延迟导致无法正常通信。在这种情况下,可能会出现多个副本都认为自己是领导者,或者无法获得多数票数导致的问题。预选举是事先发出网络请求,保证自己的网络不存在问题。

Message类型

type Message struct {
	Type             MessageType 
	To               uint64  //发往节点   
	From             uint64  //发送节点
	Term             uint64  //任期
	
	LogTerm          uint64 /*见详解(1)*/
	Index            uint64 /*见详解(1)*/
	Entries          []Entry //日志内容
	Commit           uint64 //已经提交的最新的日志索引
	Snapshot         Snapshot
	Reject           bool   //请求是否通过,也用于投票,返回是否同意发起人成为leader
	RejectHint       uint64 //follower发现日志落后,向leader发出拒绝请求,并要求同步落后的数据
	Context          []byte 
}
  1. Leader和Follower同步预写日志,为了防止Follower日志超前或落后现象,每个日志都有索引,同时Leader发出的日志会标记索引和前一篇日志任期,如果Follower前一篇的日志的Term与LogTerm不匹配,则会删去不匹配日志,LogTerm标志前面日志的任期,Index标志前面日志的索引

raftLog类型

算法模块通过<-readyC提交给应用模块,预写日志从内存到磁盘,应用模块再通过<-advanceC通知算法模块已经写入磁盘,然后算法模块会将日志状态改变为stable.
算法模块通过raftLog类型查询所有日志状态。

raftLog类型

type raftLog struct {

	// 保存最后一次快照之后提交的数据
	storage Storage
	
	//保存没有持久化的数据和快照这些数据最终会保存到storage中
	unstable unstable

	// committed is the highest log position that is known to be in
	// stable storage on a quorum of nodes.
	/*见详解(1)*/
	committed uint64
	// applied is the highest log position that the application has
	// been instructed to apply to its state machine.
	// Invariant: applied <= committed
	/*见详解(2)*/
	applied uint64

	logger Logger
}
  1. 已知被提交到足够数量节点上的稳定存储中的最高日志位置。
    highest log position:指的是日志序列中的一个索引或者偏移量,这个位置代表了最新的已处理事务或事件。
    stable storage:通常指能够持久化存储数据且即使在节点重启后仍能保持不变的存储介质,比如磁盘。
    quorum of nodes:在分布式系统中,为了保证数据的一致性和可用性,通常会使用法定人数(quorum)机制。这意味着只有当一定数量(超过半数或其他配置的数量)的节点确认收到并存储了一个日志条目时,该条目才被认为是“已提交”

  2. highest log position that the application has been instructed to apply:applied 变量表示应用(或状态机)已接收到指令并应用于其状态机的最高日志位置。这意味着所有小于等于 applied 位置的日志条目都已经在应用程序的状态机中执行完毕,影响了系统的当前状态。
    state machine:在分布式系统中,尤其是在复制状态机模型下,每个节点都维护一个状态机来处理接收到的日志条目,并据此更新自身的状态。
    Invariant: applied <= committed:表明任何时候 applied 的值都不能大于 committed。这是因为只有当一个日志条目被提交(即在法定数量节点上稳定存储)后,才能安全地应用到状态机中。这个不变式保证了即使在出现故障、网络分区或其他异常情况下,状态机也不会基于未完全确认的日志条目进行状态变更,从而确保了数据一致性。

unstable类型

type unstable struct {
	// the incoming unstable snapshot, if any.
	/*见详解(1)*/
	snapshot *pb.Snapshot
	// 没有写入磁盘的数据
	entries []pb.Entry
	//entries切片中数据的起始索引
	offset  uint64
//...
}
  1. 这个注释通常会出现在日志管理和状态机复制的相关代码中,具体指代的是尚未完全处理并应用到状态机中的“不稳定的”(incoming unstable)快照。在Raft等算法中,快照是用来压缩日志、减少存储开销,并快速同步节点状态的一种方法。

Storage接口

Storage接口出现在raftLog类型中,提供了日志查询能力

type Storage interface {

	//返回保存的初始状态
	InitialState() (pb.HardState, pb.ConfState, error)

	//返回再[lo,hi)之间并且大于maxSize的Entry切片
	Entries(lo, hi, maxSize uint64) ([]pb.Entry, error)

	//传入一个索引,返回索引对应的任期
	//错误类型包括
	//ErrCompacted 传入的索引找不到,已经被压缩成快照
	//ErrUnavaiable传入的索引值大于当前的最大索引
	Term(i uint64) (uint64, error)
	//最后一条日志的索引
	LastIndex() (uint64, error)
	// FirstIndex returns the index of the first log entry that is
	// possibly available via Entries (older entries have been incorporated
	// into the latest Snapshot; if storage only contains the dummy entry the
	// first log entry is not available).
	/*见详解(1)*/
	FirstIndex() (uint64, error)
	// ...略
}
  1. 该函数 FirstIndex() 返回首个索引值。一旦快照被创建,包含在快照中的所有先前的日志条目将不再直接可从日志存储中获取,因为它们已经被整合进最新的快照中。
    如果当前存储仅包含一个占位符或虚拟日志条目(dummy entry),那么这意味着没有可供查询的实际日志数据,因此第一个有效日志条目的索引是不可用的。在这种情况下,FirstIndex() 函数可能返回无效的索引或者是系统的下一个预期日志条目的索引。

Ready结构体

算法层处理需求后,发往应用模块的信息
算法模块同步通知应用模块的需要做什么工作的结构体Ready,Ready被ReadyCh通道传送

type Ready struct {

	// Leader身份,节点状态,只暂时保存在内存中
	*SoftState

	// 包括任期,投票归属(作为一个非leader,自己将票投给了谁),提交日志索引
	pb.HardState

	// 该函数用于当节点的应用索引大于ReadState中的索引时,可以用于本地处理线性一致性读请求。
	//当Raft接收到msgReadIndex消息时,会返回readState。返回的readState仅对请求读取的请求有效。
	ReadStates []ReadState

	// 需要应用模块持久化的预写日志
	Entries []pb.Entry

	//...

	// 已经提交的预写日志,需要应用模块应用到状态机
	CommittedEntries []pb.Entry

	// 待发送信息
	Messages []pb.Message
}

标签:uint64,etcd,goroutine,MessageType,状态机,模块,raft,日志,节点
From: https://www.cnblogs.com/ling-2945/p/18117147

相关文章

  • docker容器之etcd
    一、etcd介绍1、etcd是什么etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。2、etcd特点简单的接口,通过标准的HTTPAPI进行调用,也可以使用官方提供的etcdctl操作存储的数据。有监听机制键值对存储3、etcd是用场景......
  • 【QT+QGIS跨平台编译】045:【netcdf3+Qt跨平台编译】(一套代码、一套框架,跨平台编译)
    点击查看专栏目录文章目录一、NetCDF3介绍二、文件下载三、文件分析四、pro文件五、编译实践一、NetCDF3介绍  NetCDF(NetworkCommonDataForm)是一种用于存储科学数据的文件格式和库。NetCDF3是NetCDF的旧版本,通常指的是NetCDF版本3.x。  以下是......
  • Linux 上用 docker-compose 文件指定的方式安装ETCD
    转载自:https://xie.infoq.cn/article/ffb0703096f0de1045e1ab028,这篇博客很棒!完全可执行的。本人修改了作者docker命令替换成了dockercompose文件的方式。创建数据保存目录:mkdir-p/home/service/etcd/data;创建配置目录:/home/service/etcd/conf;配置文件:/home/service......
  • etcd与redis之间的区别
    一、简介我们之前用了redis,那么好用为什么还要来用etcd呢,这里就来和大家聊聊为什么有的业务场景选择etcd。分析:在当今的分布式系统中,数据存储及一致性相当重要。etcd和redis都是我们最受欢迎的开源分布式数据存储的解决方案,但是他们有着不同的试用场景。下面我个人对其中二个的......
  • etcd可视化连接工具
    一、官方快速上手视图工具Playground地址:http://play.etcd.io/play注释:其使用和redis差不多,主从选举模式,master节点挂了,从节点就会参与选举master,主节点可以读写,从节点只能读。二、Etcd的可视化工具etcdkeeper安装包下载地址如下:地址:https://github.com/evildecay/etcdke......
  • etcd安装(docker)
    一、拉去官方镜像dockerpullquay.io/coreos/etcd:v3.5.0二、创建etcd容器dockerrun-d\-p2379:2379\-p2380:2380\--nameetcd\quay.io/coreos/etcd:v3.5.0\/usr/local/bin/etcd\-advertise-client-urlshttp://0.0.0.0:2379\-listen-client-......
  • Etcd 基本入门
    1:什么是Etcd?Etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法,Etcd基于Go语言实现。名字由来,它源于两个方面,unix的“/etc”文件夹和分布式系统(“D”istributesystem)的D,组合......
  • 【IT老齐057】Raft选举算法
    【IT老齐057】Raft选举算法用途Raft算法是分布式系统开发首选的共识算法主要在分布式集群架构下进行领导者(主节点)的确认。比如现在流行的组件Etcd、Consul、Nacos、RocketMQ、RedisSentinel底层都是采用Raft算法来确认集群中的主节点,再通过主节点向其他节点下发指令......
  • Windows 10无法登录Xbox及其附属产品(包括但不限于Game Bar,Minecraft Launcher)
     1. 问题描述:打开Xbox(如下图) 或GameBar(如下图)  后,单击登录,会弹出一个窗口,印有自己账户的头像,下方一行小字“欢迎回来,$昵称$”,如下图所示:  单击唯一的绿色按钮“现在就开始吧”,该窗口消失,马上又回到点击登录前的界面。循环尝试结果都不变。2.解决方法第一步......
  • 查看k8s中etcd集群的状态
    1.1使用脚本下载与服务端相同版本的 etcdctl 软件包[[email protected]]$pwd/home/shutang/k8s/etcd[[email protected]]$lsdownload.sh[[email protected]]$catdownload.sh#!/bin/bashETCD_VER=v3.4.3ETCD_DIR=etcd-downloadDOWNLOAD_UR......