【ETCD】【源码阅读】stepWithWaitOption方法解析
在分布式系统中,ETCD 作为一个强一致性、高可用的 key-value 存储系统,广泛应用于服务发现、配置管理等场景。ETCD 在内部采用了 Raft 协议来保证集群的一致性,而日志预提案(log proposal)是 Raft 协议中至关重要的一部分。ETCD 在接收到 Put 请求后,会首先进行日志预提案,确保数据一致性和系统的可靠性。
本文将深入解析 ETCD 源码中的一段关键代码,stepWithWaitOption 函数,它主要负责处理 Put 请求中的日志预提案部分。我们将详细剖析这段代码的功能和设计思路,帮助您更好地理解 ETCD 如何处理 Put 请求和日志提案。
代码分析
以下是 ETCD 服务器中 stepWithWaitOption 函数的核心源码,它用于处理日志预提案:
// Step advances the state machine using msgs. The ctx.Err() will be returned,
// if any.
func (n *node) stepWithWaitOption(ctx context.Context, m pb.Message, wait bool) error {// 如果消息类型不是 MsgProp,则将消息直接发送到接收通道if m.Type != pb.MsgProp {select {case n.recvc <- m:return nilcase <-ctx.Done():return ctx.Err()case <-n.done:return ErrStopped}}// 如果是 MsgProp 消息类型,进行日志预提案ch := n.propcpm := msgWithResult{m: m}// 如果需要等待结果,创建一个带缓冲的通道用于接收错误if wait {pm.result = make(chan error, 1)}// 将消息放入提案通道select {case ch <- pm:// 如果不需要等待结果,立即返回if !wait {return nil}case <-ctx.Done():return ctx.Err()case <-n.done:return ErrStopped}// 等待处理结果select {case err := <-pm.result:if err != nil {return err}case <-ctx.Done():return ctx.Err()case <-n.done:return ErrStopped}return nil
}
1. 消息类型判断与处理
在 ETCD 中,日志预提案的核心是通过 MsgProp 类型的消息来进行的。首先,函数检查传入的消息类型是否为 pb.MsgProp(即提案消息)。如果消息类型不是 MsgProp,则直接将消息发送到 n.recvc 通道。
if m.Type != pb.MsgProp {select {case n.recvc <- m:return nilcase <-ctx.Done():return ctx.Err()case <-n.done:return ErrStopped}
}
如果消息类型不是 MsgProp,那么说明这不是一个日志提案请求,因此直接将消息发送到接收通道 n.recvc,并根据上下文的取消信号或状态机的停止信号判断是否需要退出。
2. 日志提案与等待选项
如果消息类型是 MsgProp,说明这是一个日志预提案请求,函数会进入更复杂的逻辑。首先,创建一个 msgWithResult 结构体,该结构体包含消息本身和一个可选的错误通道 result。如果需要等待结果(wait 为 true),我们为 msgWithResult 创建一个缓冲的错误通道。
ch := n.propc
pm := msgWithResult{m: m}
if wait {pm.result = make(chan error, 1)
}
在这一部分,propc 是用于存储提案消息的通道,它会负责将消息发送到适当的处理函数。这里,我们根据是否需要等待结果来决定是否创建一个错误通道。如果需要等待结果,我们稍后会从该通道读取处理结果。
3. 发送提案消息到通道
接下来,使用 select 语句将消息发送到提案通道 ch。如果没有等待结果(wait == false),则消息发送成功后立即返回。如果需要等待结果,我们会在发送消息后继续执行,等待处理结果。
select {
case ch <- pm:if !wait {return nil}
case <-ctx.Done():return ctx.Err()
case <-n.done:return ErrStopped
}
在这里,我们检查是否有任何取消操作发生,或者状态机是否已经停止。如果没有,则将消息发送到提案通道,并根据 wait 参数决定是否立即返回或继续等待结果。
4. 等待处理结果
如果需要等待处理结果(wait == true),函数会进入第二个 select 语句,等待从 pm.result 通道中接收到处理结果。如果处理结果是错误,则返回该错误;如果在等待过程中上下文被取消或状态机停止,函数也会提前返回相应的错误。
select {
case err := <-pm.result:if err != nil {return err}
case <-ctx.Done():return ctx.Err()
case <-n.done:return ErrStopped
}
5. 上下文与停止条件
在整个函数的实现过程中,我们多次使用 ctx.Done() 和 n.done 来监听上下文的取消和状态机的停止。上下文取消和状态机停止是确保在长时间运行的操作中能够及时响应外部信号,避免资源泄露或无意义的操作。
case <-ctx.Done():return ctx.Err()
case <-n.done:return ErrStopped
这两条语句确保了在出现异常或超时的情况下,我们能够安全退出并处理错误。
总结
ETCD 服务器的 stepWithWaitOption 函数是处理日志预提案的关键部分。它结合了消息传递、上下文控制和并发管理,确保系统能够在高并发和分布式环境中稳定运行。通过 select 语句的巧妙使用,ETCD 能够在不同的条件下(如上下文取消、状态机停止等)做出及时的响应。
在这篇文章中,我们详细解析了这段代码的工作原理,希望能帮助大家更好地理解 ETCD 如何通过 Raft 协议和日志提案机制来实现一致性。ETCD 的设计和实现展示了如何在复杂的分布式系统中,通过细致的并发控制和上下文管理来确保高效、可靠的服务。
如果你对 ETCD 或 Raft 协议有更多的疑问,或者想深入了解其他 ETCD 源码的实现,欢迎在评论区与我交流!
相关文章:
【ETCD】【源码阅读】stepWithWaitOption方法解析
在分布式系统中,ETCD 作为一个强一致性、高可用的 key-value 存储系统,广泛应用于服务发现、配置管理等场景。ETCD 在内部采用了 Raft 协议来保证集群的一致性,而日志预提案(log proposal)是 Raft 协议中至关重要的一部…...
redis 怎么样查看list
在 Redis 中,可以通过以下方法查看列表的内容或属性: 1. 查看列表中的所有元素 使用 LRANGE 命令: LRANGE key start endkey 是列表的名称。start 是起始索引,0 表示第一个元素。end 是结束索引,-1 表示最后一个元素…...
E: 无法获取 dpkg 前端锁 (/var/lib/dpkg/lock-frontend),是否有其他进程正占用它?
我们在使用Ubuntu系统时经常性使用sudo apt install命令安装所需要的软件库,偶尔会出现如下问题: E: 无法获得锁 /var/lib/dpkg/lock-frontend - open (11: 资源暂时不可用) E: 无法获取 dpkg 前端锁 (/var/lib/dpkg/lock-frontend),是否有其…...
创建型设计模式
一、设计模式介绍 1.设计模式是什么 设计模式是指在软件开发中,经过验证的,用于解决在特定环境下,重复出现的,特定问题的解决方案; 2.设计模式怎么来的? 满足设计原则后,慢慢迭代出来的。 3.设…...
仿iOS日历、飞书日历、Google日历的日模式
仿iOS日历、飞书日历、Google日历的日模式,24H内事件可自由上下拖动、自由拉伸。 以下是效果图: 具体实现比较简单,代码如下: import android.content.Context; import android.graphics.Canvas; import android.graphics.Color;…...
vuedraggable
官方文档:https://www.npmjs.com/package/vuedraggable 中文文档:http://www.itxst.com/vue-draggable/tutorial.html 案例下载地址: https://github.com/SortableJS/Vue.Draggable.git vuedraggablehttps://sortablejs.github.io/Vue.Dr…...
新手从事直播软件源码开发搭建经验与技巧
如果从YY或六间房的PC秀场直播间系统软件算起,直播软件已经在国内风云了至少10年了,站在用户角度提到直播系统大家基本都知道核心功能有开直播刷礼物等,那么如果站在直播软件源码开发搭建的技术角度去看呢?是不是要从需求调研分析…...
相机不动,机构动作----Hands Eyes
最近在研究 手眼标定,发现大家都需付费,搞啥子,说好的开源。。。 以相机在上固定不动,机械手为 EPSON_Robot 为例,详细的一步一步实例操作指引 EPSON_Robot 的192.168.0.1 2004 Server 详细操作步骤 1. 启动程序 运…...
Scala的导入
//导入 //(1) 创建包:在src上右键,新建软件包 //(2)填写包名:小写 //(3)在包上右键,创建类。自动加入包名 //(4)导入。import 包名.类名 //导入多个类 //import jh.yuanlixueyuan.bigdata.scala03.{A,B,C} //导入包下的所有的类 /…...
vue2中父子组件传值案例总结
在 Vue 2 中,父子组件之间的传值是通过 props 和事件来实现的。下面是详细的解释和总结: 1. 父组件向子组件传值 父组件可以通过 props 向子组件传递数据。以下是一个简单的示例: 父组件 (Parent.vue) <template><div><h1…...
功能篇:springboot中实现文件导出
### Spring Boot 中实现文件导出功能 #### 概述 在现代Web应用程序中,文件导出是一个常见的需求,允许用户将数据以特定格式(如CSV、Excel、PDF等)下载到本地。本文将详细介绍如何使用Spring Boot实现文件导出功能,并…...
Redis客户端(Jedis、RedisTemplate、Redisson)
1. 简介 Redis作为一个当下很火热的非关系型数据库,Java从业人员基本都离不开对Redis的使用。在Java程序中该数据库,需要借助于市面上的开源客户端,如Jedis、Spring Data Redis、Redisson,它们可以作为操作Redis非关系型数据库的桥…...
Mybatis中SQL的执行过程
文章目录 Mybatis 框架SQL执行过程数据库操作映射方式SQL的执行过程- SQL解析- SQL参数映射- SQL预编译- SQL执行- 结果映射- 事务处理- 缓存处理- 日志记录与监控 扩展#与$的区别- $ 符号- # 符号总结示例 Mybatis SQL分类- 动态 SQL- 静态 SQL静态SQL和动态SQL选择${}、#{}与…...
【数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
目录😋 任务描述 相关知识 测试说明 我的通关代码: 测试结果: 任务描述 本关任务:编写一个程序实现顺序栈的基本运算。 相关知识 为了完成本关任务,你需要掌握: 初始化栈、销毁栈、判断栈是否为空、进栈、出栈、取…...
【论文阅读】PRIS: Practical robust invertible network for image steganography
内容简介 论文标题:PRIS: Practical robust invertible network for image steganography 作者:Hang Yang, Yitian Xu∗, Xuhua Liu∗, Xiaodong Ma∗ 发表时间:2024年4月11日 Engineering Applications of Artificial Intelligence 关键…...
在Linux桌面系统普及化方面的一些建议
在推动Linux桌面系统普及化的过程中,可以考虑以下几个方案和策略: 用户友好性改进: 界面设计:提升用户界面的美观性和易用性,使其更接近或超越主流操作系统的用户体验。软件兼容性:确保常用软件(…...
LLM - 多模态大模型的开源评估工具 VLMEvalKit 部署与测试 教程
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/144353087 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 VLMEva…...
数据结构(Queue队列)
前言: 在计算机科学中,数据结构是构建高效算法和程序的基础,而队列(Queue)作为一种经典的线性数据结构,具有重要的地位。与栈(Stack)不同,队列遵循“先进先出”…...
Qt 图形框架下图形拖动后位置跳动问题
在使用Qt 的图形框架QGraphicsScene,QGraphicsView实现图形显示时。遇到一个很棘手的BUG。 使用的图形是自定义的QGraphicsObject的子类。 现象是将图形添加到画布上之后,用鼠标拖动图形,图形能正常改变位置,当再次用鼠标点击图…...
【Linux篇】走进Linux — 开启开源操作系统之旅
文章目录 初识Linux一.Linux的起源与发展二.Linux的特点三.Linux的应用四.Linux的发行版本 Linux环境搭建一.Linux环境的搭建方式二.购买云服务器三.使用XShell远程登陆到Linux 初识Linux 一.Linux的起源与发展 1.初始动机: Linux是一个功能强大的开源操作系统&am…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...
