首页 > 编程语言 >raft算法和etcd代码解析-5.应用模块的启动

raft算法和etcd代码解析-5.应用模块的启动

时间:2024-05-03 12:45:14浏览次数:28  
标签:Node etcd 算法 模块 rc raft ID

Node接口

Node是raft应用模块在节点上的抽象,也是应用模块和算法模块交互的入口
应用模块持有Node作为算法模块的引用,通过调用Node接口的API与算法模块通信,通信方式是通过若干个Channel异步完成的。

// Node represents a node in a raft cluster.
type Node interface {
	// 告知算法模块时间
	Tick()
	// 告知需要参与竞选
	Campaign(ctx context.Context) error
	// 发送写请求
	Propose(ctx context.Context, data []byte) error
	// 发送配置变更请求
	ProposeConfChange(ctx context.Context, cc pb.ConfChange) error
	
	// ...

	Ready() <-chan Ready

	// Ready任务之后,通知算法模块
	Advance()
	// 应用模块感知到应用变更被集群认可
	ApplyConfChange(cc pb.ConfChange) *pb.ConfState

	// ...

	// 读请求
	ReadIndex(ctx context.Context, rctx []byte) error

	// ...
}

ReadyOnly

读请求全部由leader处理

type readIndexStatus struct {
	//封装读请求的消息体
	req   pb.Message
	//leader已提交日志索引
	index uint64
	//Leader收到的节点响应,实际上是个Set类型
	//为了防止网络同步时失误而存在多个leader的结果
	//leader需要向其他follower告知自己身份,以期得到多数派响应,证明leader身份是合法的
	//acks就是用来收集其他follower响应
	acks  map[uint64]struct{}
}

type readOnly struct {
	option           ReadOnlyOption
	//使用entry数据当作key,保存读请求队列中的读请求的状态
	pendingReadIndex map[string]*readIndexStatus
	//将多个读请求放入队列,依次处理
	readIndexQueue   []string
}

startRaft方法

func (rc *raftNode) startNode() {
	//...
	
	// 获取集群其他raft信息
	rpeers := make([]raft.Peer, len(rc.peers))
	for i := range rpeers {
		rpeers[i] = raft.Peer{ID: uint64(i + 1)}
	}
	// 构造raft配置的实例给算法层 
	c := &raft.Config{
		ID: uint64,  // 当前节点ID
		ElectionTick: 10, // 选举时间 10个tick加上随机扰动值后发起选举
		HeartbeatTick: 1, // 广播心跳时间
		Storage: rc.raftStore // 应用层给算法层的存储接口 算法层可通过此查询存储
	}
	// 集群信息
	startPeers := rpeers
	//启动算法层的node
	rc.node = raft.StartNode(c, startPeers)
	
	// ...
	
	rc.transport = &rafthttp.Transport{
		ID: types.ID(rc.id),
		ClusterID: 0x1000,
		Raft: rc,
		ServerStats: ss,
		LeaderStats: stats.NewLeaderStats(strconv.Itoa(rc.id)),
		ErrorC: make(chan error),
	}
	// raft节点之间的通信
	rc.transport.Start()
	for i := range rc.peers {
		if i+1 != rc.id {
			rc.transport.AddPeer(types.ID(i+1), []string{rc.peers[i]})
		}
	}
	// 启动通行
	go rc.serveRaft()
	// 异步开启raftNoide的主循环 用于与算法层的goroutine建立持续通信关系
	go rc.serveChannel
}

serveChannel方法

serveChannel方法有两处阻塞监听

func (rc *raftNode) serveChannels() {
	// ...

	// 这里定义一个ticker 为 100ms
	ticker := time.NewTicker(100 * time.Millisecond)
	defer ticker.Stop()

	// 接受客户端请求 传送到算法层
	go func() {
		var confChangeCount uint64 = 0

		for rc.proposeC != nil && rc.confChangeC != nil {
			select {
			// 客户端写请求
			case prop, ok := <-rc.proposeC:
				if !ok {
					rc.proposeC = nil
				} else {
					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)
				}
			}
		}
		// client closed channel; shutdown raft if not already
		close(rc.stopc)
	}()

	// 接受算法层关于日志持久化的信息
	for {
		select {
		// 监听ticker 并发送给算法模块 让算法模块感知时间
		case <-ticker.C:
			rc.node.Tick()
		// 接受算法层要求
		case rd := <-rc.node.Ready():
			// 预写日志持久化
			rc.raftStorage.Append(rd.Entries)
			// f调用模块 例如发送邮件信息
			rc.transport.Send(rd.Messages)
			// 将预写日志应用到状态机
			if okI := rc.publishEntries(rc.entriesToApply(rd.CommittedEnttries)); ok {
				rc.stop()
				return
			}
			// 告知算法模块 已完成预写日志持久化
			rc.node.Advance()
			//...
		}
	}
}

标签:Node,etcd,算法,模块,rc,raft,ID
From: https://www.cnblogs.com/ling-2945/p/18171121

相关文章

  • Etcd因磁盘IO高而写操作慢
    问题现象now:=time.Now()iferr:=kubeClient.CoreV1().Pods("default").Delete(context.Background(),"busybox-7879d986c8-q99t5",metav1.DeleteOptions{});err==nil{ klog.Infof("deletepodsuccess,cost%dms",time.Since(now)......
  • 启动 Minecraft Forge 服务器
    ThispagewillteachtheplayerhowtoinstallaForgeserver.1.6to1.20.2TextversionFirstly,youneedtheForgeinstaller,whichcanbedownloadedfromtheofficialForgedownloadpage.Oncedownloaded,launchitandchooseoption"Installserv......
  • C#的基于.net framework的Dll模块编程(五) - 编程手把手系列文章
          这次继续这个系列的介绍: 一、使用DLL类库的方法;1)静态类;先引用该类库,然后声明命名空间,然后就能够进行使用了。   2)动态类;先引用该类库,然后声明命名空间,然后能够进行使用了。  3)窗体;只能在Winf......
  • Python - 模块包
    目录包导入示例包的from语句vs包的import语句包导入示例下列三个文件分别位于目录dir1以及dir1的子目录dir2中,这些文件的路径名在注释中给出:#dir1\__init__.pyprint('dir1init')x=1#dir1\dir2\__init__.pyprint('dir2init')y=2#dir1\dir2\mod.pypr......
  • LoRa模块在智能灌溉系统中的应用特点介绍
    LoRa模块在智能灌溉系统中的应用特点主要体现在以下几个方面:低功耗与长寿命:LoRa模块具有极低的功耗,使其在待机状态下耗电量极低,能够支持长时间连续运行,减少了频繁更换电池或充电的需求,确保了智能灌溉系统的长期稳定运行。远程监控与控制:通过LoRa模块构建的无线通信网络,可......
  • 无线模块透明传输原理及过程解析
    透明传输,顾名思义,是指在传输过程中对外界完全透明,不需要关注传输过程以及传输协议,最终目的是要把传输的内容原封不动地传递给接收端,发送和接收的内容完全一致。在无线模块中,透明传输通常是通过特定的技术和机制来实现的。无线模块透明传输的原理主要基于串口数据的透明传输。这种......
  • 无线模块空中唤醒技术原理详解
    空中唤醒功能,英文名称为WakeonRadio(WOR),其原理主要是通过减少接收端射频处于接收状态的时间,而在其余时间使设备处于深度睡眠模式,以此来实现设备功耗的显著降低。这种机制确保了设备在不需要接收数据时保持低功耗状态,而在需要接收数据时能够迅速被唤醒至接收状态。具体来说,空......
  • BOSHIDA AC/DC电源模块的电磁兼容性分析与方案设计
    BOSHIDAAC/DC电源模块的电磁兼容性分析与方案设计BOSHIDAAC/DC电源模块是一种将交流电转换为直流电的电源模块,常用于各种电子设备中。然而,由于电磁干扰可能会对设备的正常运行造成影响,因此需要对AC/DC电源模块的电磁兼容性进行分析和方案设计。 首先,我们需要对AC/DC电源模......
  • TypeScript入门5:模块化(导入导出)
    1.概述2.语法3.避免命名冲突4.默认导入导出......
  • Python重试任务模块tenacity
    1.简介在实际应用中,经常会碰到在web请求时,因为网络的不稳定,会有请求超时的问题,这时候,一般都是自己去实现重试请求的逻辑,直到得到响应或者超时。虽然这样的逻辑并不复杂,但是代码写起来却不那么优雅,不那么pythonic。tenacity是一个重试库,使用python语言编写,它能够让我们在任务的重......