05、etcd 读请求执行流程
本篇内容主要来源于自己学习的视频,如有侵权,请联系删除,谢谢。
1、etcd读请求概览
etcd是典型的读多写少存储,在我们实际业务场景中,读一般占据2/3以上的请求。一个读 请求从client通过Round-robin(轮询)负载均衡算法,选择一个etcd server节点,发出 gRPC请 求,经过etcd server的 KVServer模块、线性读模块、MVCC的treelndex和 boltdb模块紧 密协作,完成了一个读请求。

思考:通过etcdctl执行如下命令etcd是如何工作的?
etcdctl get hello ‐‐endpoints 192.168.65.210:2379,192.168.65.211:2379,19 2.168.65.212:2379
2、详细步骤解读
2.1 Client 层
主要是对应到步骤 1
1、首先,etcdctl 会对命令中的参数进行解析。
get是请求的方法,它是 KVServer 模块的 提供的API;hello是 我们查询的 key 名;endpoints是我们后端的 etcd 地址。通常,生产环境下中需要配置多个endpoints,这样在 etcd 节点出现故障后,client 就可以自动重连到其它正常的节点,从而保证请求的正常执行。
2、在解析完请求中的参数后,etcdctl 会创建一个 clientv3 库对象,使用 KVServer 模块 的 API 来访问 etcd server。
etcd clientv3 库采用的负载均衡算法为 Round-robin。针对每一个请求,Round-robin 算法通过轮询的方式依次从 endpoint 列表中选择一个 endpoint 访问 (长连接),使 etcd server 负载尽量均衡。
2.2 KVServer 与 拦截器
主要是对应到步骤 2
client 发送 Range RPC 请求到了 server 后就进入了 KVServer 模块。
etcd 通过拦截器以非侵入式的方式实现了许多特性,例如:丰富的 metrics、日志、请求行为检查、所有请求的执行耗时及错误码、来源IP 等。拦截器提供了在执行一个请求前后 的 hook 能力,除了 debug 日志、metrics 统计、对 etcd Learner 节点请求接口和参数限制等能力,etcd 还基于它实现了以下特性:
要求执行一个操作前集群必须有 Leader;
请求延时超过指定阈值的,打印包含来源 IP 的慢查询日志 (3.5 版本)。
server 收到 client 的 Range RPC 请求后,根据 ServiceName 和 RPC Method 将请求转 发到对应的 handler 实现,handler 首先会将上面描述的一系列拦截器串联成一个拦截器再执行,在拦截器逻辑中,通过调用 KVServer 模块的 Range 接口获取数据。
2.3 串行读与线性读
流程三和四.
etcd 为了保证服务高可用,生产环境一般部署多个节点,多节点之间的数据由于延迟等关系可能会存在不一致的情况。
当 client 发起一个写请求后分为以下几个步骤:
1、Leader 收到写请求,它会将此请求持久化到 WAL 日志,并广播给各个节点;
只有 Leader 节点能处理写请求。
2、若一半以上节点持久化成功,则该请求对应的日志条目被标识为已提交;
3、etcdserver 模块异步从 Raft 模块获取已提交的日志条目,应用到状态机 (boltdb 等)。

此时若client 发起一个读取 hello 的请求,假设此请求直接从状态机中读取,如果连接到的是C节点,若C节点磁盘I/O出现波动,可能导致它应用已提交的日志条目很慢,则会出现更新 hello 为 world 的写命令,在client读 hello 的时候还未被提交到状态机,因此就可能读取到旧数据,如上图查询hello流程所示。
所以在多节点etcd集群中,各个节点的状态机数据一致性存在差异。而我们不同业务场景 的读请求对数据是否最新的容忍度是不一样的,有的场景它可以容忍数据落后几秒甚至几分 钟,有的场景要求必须读到反映集群共识的最新数据。根据业务场景对数据一致性差异的接受程度。
**etcd 中有两种读模式: **
1、串行 (Serializable) 读:
直接读状态机数据返回、无需通过 Raft 协议与集群进行交互, 它具有低延时、高吞吐量的特点,适合对数据一致性要求不高的场景。
2、线性读:
etcd
默认读模式是线性读,需要经过 Raft 协议模块,反应的是集群共识,因 此在延时和吞吐量上相比串行读略差一点,适用于对数据一致性要求高的场景。
对数据敏感度较低的场景:
- 直接读状态机数据返回、无需通过 Raft 协议与集群进行交互的模式,在 etcd 里叫做串行 (Serializable) 读,它具有低延时、高吞吐量的特点,适合对数据一致性要求不高的场景。
对数据敏感性高的场景:
- 在 etcd 里面,提供了一种线性读模式来解决对数据一致性要求高的场景。
什么是线性读呢?
你可以理解一旦一个值更新成功,随后任何通过线性读的 client 都能及时访问到。虽然集群中有多个节点,但 client 通过线性读就如访问一个节点一样。etcd 默认读模式是线性读,因为它需要经过 Raft 协议模块,反应的是集群共识,因此在延时和吞吐量上相比串行读略差一点,适用于对数据一致性要求高的场景。
2.4 ReadIndex
在 etcd 3.1 引入了 ReadIndex 机制,保证在串行读的时候,也能读到最新的数据。
接下来看看线性读的执行流程

具体流程如下:
当收到一个线性读请求时,它
首先会从Leader获取集群最新的已提交的日志索引(committed index),如上图中的流程二所示。Leader收到
ReadIndex请求时,为防止脑裂等异常场景,会向Follower节点发送心跳确认,一半以上节点确认Leader身份后才能将已提交的索引(committed index)返回给节点C(上图中的流程三)。节点则会等待,直到
状态机已应用索引 (applied index)大于等于Leader的已提交索引时(committed Index)(上图中的流程四),然后去通知读请求,数据已赶上 Leader,你可以去状态机中访问数据了(上图中的流程五)。
以上就是线性读通过ReadIndex机制保证数据一致性原理,当然还有其它机制也能实现线性读,如在早期etcd 3.0中读请求通过走一遍Raft 协议保证一致性,这种Raft log read机制 依赖磁盘IO,性能相比 ReadIndex较差。
总体而言,KVServer模块收到线性读请求后,通过架构图中流程三向Raft模块发起 ReadIndex请求,Raft模块将Leader最新的已提交日志索引封装在流程四的ReadState结构体,通过channel层层返回给线性读模块,线性读模块等待本节点状态机追赶上Leader进度,追赶完成后,就通知KVServer模块,进行架构图中流程五,与状态机中的 MVCC模块进行进行交互了。
2.5 MVCC
流程五中的多版本并发控制(Multiversion concurrency control)模块是为了解决etcd v2不支持保存key的历史版本、不支持多key事务等问题而产生的。它核心由内存树形索引模块 (treelndex)和嵌入式的KV持久化存储库 boltdb 组成。boltdb是个基于B+ tree实现的 key-value键值库,支持事务,提供Get/Put等简易API给etcd操作。
etcd MVCC 具体方案如下:
- 每次修改操作,生成一个
新的版本号 (revision),以版本号为 key, value 为用户 key-value 等信息组成的结构体存储到 blotdb。 - 读取时·先从 treeIndex 中获取 key 的版本号·,再以版本号作为 boltdb 的 key,从 boltdb 中获取其 value 信息。

2.6 treelndex
treelndex模块是基于Google开源的内存版btree 库实现的,treeIndex模块只会保存用户的key和相关版本号信息,用户 key 的value数据存储在boltdb里面,相比ZooKeeper和 etcd v2全内存存储,etcd v3对内存要求更低。
简单介绍了etcd如何保存 key的历史版本后,架构图中流程六也就非常容易理解了,它需要从treelndex模块中获取 hello这个 key对应的版本号信息。treeIndex模块基于 B-tree快速查找此 key,返回此 key对应的索引项keyIndex即可。索引项中包含版本号等信息。
2.7 buffer
在获取到版本号信息后,就可从boltdb模块中获取用户的key-value数据了。不过并不是所有请求都—定要从 boltdb 获取数据。etcd出于数据一致性、性能等考虑,在访问boltdb前,首先会从一个内存读事务 buffer中,二分查找你要访问key是否在 buffer里面,若命中则直接返回。
2.8 boltdb
若buffer未命中,此时就真正需要向boltdb模块查询数据了,进入了流程七。 我们知道MySQL通过 table 实现不同数据逻辑隔离,那么在boltdb是如何隔离集群元数据 与用户数据的呢?答案是bucket。
boltdb 里每个 bucket 类似对应 MySQL 一个表,用户的 key 数据存放的 bucket 名字的是 key,etcd MVCC 元数据存放的 bucket 是 meta。
我猜测这里的意思是每个key都当做一个 bucket,然后bucket的名字是 key。这里是猜测的,待验证,若有知道的朋友,请不吝赐教,十分感谢。
因boltdb使用B+ tree来组织用户的key-value数据,获取 bucket key对象后,通过boltdb 的游标Cursor可快速在B+ tree找到 key hello对应的value数据,返回给client。 到这里,一个读请求之路执行完成。
文章来源:
05、etcd 读请求执行流程的更多相关文章
- Spring MVC请求执行流程
学习Spring MVC时间有点长了,但是最近打算找工作,需要重新了解下,所以又去温故知新了.Spring MVC就是用来写web的框架,简化你写web的一些不必要的流程,让程序员能专注于业务逻辑也就 ...
- springmvc对请求执行流程
doService-->getHandlerMapping-->handlerMapping-->getHandler-->HandlerExecutionChain--> ...
- 一文读懂Spring MVC执行流程
说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: ...
- Java——一文读懂Spring MVC执行流程
说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: Sp ...
- 040 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 02 while循环的执行流程
040 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 02 while循环的执行流程 本文知识点:while循环的执行流程 三种循环结构中的第一种--wh ...
- am335x uboot2016.05 (MLO u-boot.img)执行流程
am335x的cpu上电后,执行流程:ROM->MLO(SPL)->u-boot.img 第一级bootloader:引导加载程序,板子上电后会自动执行这些代码,如启动方式(SDcard. ...
- am335x uboot2016.05 (MLO u-boot.img)执行流程(转)
am335x的cpu上电后,执行流程:ROM->MLO(SPL)->u-boot.img 第一级bootloader:引导加载程序,板子上电后会自动执行这些代码,如启动方式(SDcard. ...
- 追源索骥:透过源码看懂Flink核心框架的执行流程
li,ol.inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt, ...
- Spring Security 案例实现和执行流程剖析
Spring Security Spring Security 是 Spring 社区的一个顶级项目,也是 Spring Boot 官方推荐使用的安全框架.除了常规的认证(Authentication ...
- {Django基础九之中间件} 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证
Django基础九之中间件 本节目录 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证 六 xxx 七 xxx 八 xxx 一 前戏 我们在前面的课程中已经学会了 ...
随机推荐
- [转帖]如何在本地编译安装部署自动化回归测试平台 AREX
https://zhuanlan.zhihu.com/p/613877597 AREX 官方 QQ 交流群:656108079 本文将详细为大家介绍一下自动化回归测试平台 AREX 以及如何在本地进行 ...
- vim配置的学习与总结
摘要 有时候在linux里面操作需要使用粘贴以及其他处理. 很多发行版, 遇到 # 会自动退格, 很难受. 想着能够处理一下vim的默认设置可以好很多. 所以这里简单总结一下. 配置文件 vim的配置 ...
- 重磅文章:VictoriaMetrics存储引擎分析.pdf
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 万字长文,详细介绍 VictoriaMetrics 存储引 ...
- 初试高云FPGA
前言 之前一直眼馋Sipeed的Tang系列,正好遇到有工程需要高速控制并行总线,就买了NANO 9K和Primer 20K试试水 买回来先拆的贵的20k,结果发现Sipeed设计师有奇怪的脑回路: ...
- 错误的daemon.json配置,导致docker容器启动失败 Failed to start Docker Application Container Engine
docker学习-配置错误的源 问题点剖析 参考 docker学习-配置错误的源 问题点剖析 使用docker安装了nginx,编写Dockerfile,映射端口,终于跑起来了.但是,当我重启服务器, ...
- Mybatis(一对一、一对多、多对多)操作
* 首先列出示例中用到的数据库表 user表: accout表: role表: user_role表: 建表语句如下: DROP TABLE IF EXISTS `user`; CREATE TABL ...
- ubuntu系统单网卡配置多网段IP
环境 系统版本:Ubuntu 16.04.5 LTS 配置 ubuntu系统网卡文件是interfaces,修改网卡配置文件vim /etc/network/interfaces添加2个IP地址: a ...
- 【链表】单链表的介绍和基本操作(C语言实现)【保姆级别详细教学】
单链表 文章目录 前言 单链表基本介绍 基本结构 与顺序表的区别以及学习单链表的必要性 单链表的实现 结点的定义以及头指针的创建 单链表的遍历(打印接口的实现)[重点] 开辟结点接口 尾插接口 尾删接 ...
- 求助:Docker怎么连接mongoDB?
首先 在playwithDocker中通过docker pull mongo引入mongo 然后创建容器 docker run -it --name mymongo -p 27017:27017 -v ...
- 素数打表,洛谷P1217 [USACO1.5]回文质数 Prime Palindromes
这道题的最后一个样例TLE(超时)了,判断素数的条件是 i*i<n 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include ...