【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…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...