etcd 实战课
唐聪
腾讯云资深工程师,etcd 活跃贡献者
4278 人已学习
立即订阅
登录后,你可以任选3讲全文学习
推荐试读
换一换
03 | 基础架构:etcd一个写请求是如何执行的?
04 | Raft协议:etcd如何实现高可用、数据强一致的?
08 | Watch:如何高效获取数据变化通知?
课程目录
已完结/共 28 讲
开篇词 (1讲)
开篇词|为什么你要学习etcd?
基础篇 (11讲)
01 | etcd的前世今生:为什么Kubernetes使用etcd?
02 | 基础架构:etcd一个读请求是如何执行的?
03 | 基础架构:etcd一个写请求是如何执行的?
04 | Raft协议:etcd如何实现高可用、数据强一致的?
05 | 鉴权:如何保护你的数据安全?
06 | 租约:如何检测你的客户端存活?
07 | MVCC:如何实现多版本并发控制?
08 | Watch:如何高效获取数据变化通知?
09 | 事务:如何安全地实现多key操作?
10 | boltdb:如何持久化存储你的key-value数据?
11 | 压缩:如何回收旧版本数据?
实践篇 (13讲)
12 | 一致性:为什么基于Raft实现的etcd还会出现数据不一致?
13 | db大小:为什么etcd社区建议db大小不超过8G?
14 | 延时:为什么你的etcd请求会出现超时?
15 | 内存:为什么你的etcd内存占用那么高?
16 | 性能及稳定性(上):如何优化及扩展etcd性能?
17 | 性能及稳定性(下):如何优化及扩展etcd性能?
18 | 实战:如何基于Raft从0到1构建一个支持多存储引擎分布式KV服务?
19 | Kubernetes基础应用:创建一个Pod背后etcd发生了什么?
20 | Kubernetes高级应用:如何优化业务场景使etcd能支撑上万节点集群?
21 | 分布式锁:为什么基于etcd实现分布式锁比Redis锁更安全?
22 | 配置及服务发现:解析etcd在API Gateway开源项目中应用
23 | 选型:etcd/ZooKeeper/Consul等我们该如何选择?
24 | 运维:如何构建高可靠的etcd集群运维体系?
特别放送 (1讲)
特别放送 | 成员变更:为什么集群看起来正常,移除节点却会失败呢?
结课测试 (1讲)
结课测试题|这些相关etcd知识你都掌握了吗?
结束语 (1讲)
结束语 | 搞懂etcd,掌握通往分布式存储系统之门的钥匙
etcd 实战课
15
15
1.0x
00:00/00:00
登录|注册
开通超级会员可免费学习本课程,还可解锁海量内容免费学特权。

02 | 基础架构:etcd一个读请求是如何执行的?

你好,我是唐聪。
在上一讲中,我和你分享了 etcd 的前世今生,同时也为你重点介绍了 etcd v2 的不足之处,以及我们现在广泛使用 etcd v3 的原因。
今天,我想跟你介绍一下 etcd v3 的基础架构,让你从整体上对 etcd 有一个初步的了解,心中能构筑起一幅 etcd 模块全景图。这样,在你遇到诸如“Kubernetes 在执行 kubectl get pod 时,etcd 如何获取到最新的数据返回给 APIServer?”等流程架构问题时,就能知道各个模块由上至下是如何紧密协作的。
即便是遇到请求报错,你也能通过顶层的模块全景图,推测出请求流程究竟在什么模块出现了问题。

基础架构

下面是一张 etcd 的简要基础架构图,我们先从宏观上了解一下 etcd 都有哪些功能模块。
你可以看到,按照分层模型,etcd 可分为 Client 层、API 网络层、Raft 算法层、逻辑层和存储层。这些层的功能如下:
Client 层:Client 层包括 client v2 和 v3 两个大版本 API 客户端库,提供了简洁易用的 API,同时支持负载均衡、节点间故障自动转移,可极大降低业务使用 etcd 复杂度,提升开发效率、服务可用性。
API 网络层:API 网络层主要包括 client 访问 server 和 server 节点之间的通信协议。一方面,client 访问 etcd server 的 API 分为 v2 和 v3 两个大版本。v2 API 使用 HTTP/1.x 协议,v3 API 使用 gRPC 协议。同时 v3 通过 etcd grpc-gateway 组件也支持 HTTP/1.x 协议,便于各种语言的服务调用。另一方面,server 之间通信协议,是指节点间通过 Raft 算法实现数据复制和 Leader 选举等功能时使用的 HTTP 协议。
Raft 算法层:Raft 算法层实现了 Leader 选举、日志复制、ReadIndex 等核心算法特性,用于保障 etcd 多个节点间的数据一致性、提升服务可用性等,是 etcd 的基石和亮点。
功能逻辑层:etcd 核心特性实现层,如典型的 KVServer 模块、MVCC 模块、Auth 鉴权模块、Lease 租约模块、Compactor 压缩模块等,其中 MVCC 模块主要由 treeIndex 模块和 boltdb 模块组成。
存储层:存储层包含预写日志 (WAL) 模块、快照 (Snapshot) 模块、boltdb 模块。其中 WAL 可保障 etcd crash 后数据不丢失,boltdb 则保存了集群元数据和用户写入的数据。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/1000字
划线
笔记
复制
03 | 基础架构:etcd一个写请求是如何执行的?
04 | Raft协议:etcd如何实现高可用、数据强一致的?
08 | Watch:如何高效获取数据变化通知?
12 | 一致性:为什么基于Raft实现的etcd还会出现数据不一致?
16 | 性能及稳定性(上):如何优化及扩展etcd性能?
21 | 分布式锁:为什么基于etcd实现分布式锁比Redis锁更安全?
开通超级会员免费畅看本课程
开通会员
该文章仅可免费阅读部分内容,如需阅读完整文章,请开通超级会员或单独购买本课程。
登录 后留言

精选留言(56)

  • hiroshi
    老师,readIndex 需要请求 leader,那为啥不直接让 leader 返回读请求的结果,而要等待自己的进度赶上 leader?

    作者回复: 非常好的问题,我个人认为主要还是性能因素,我记得etcd v2早期的时候如果你指定线性读/共识读,它就是直接转发给leader的。后来在etcd v3.0中实现了raft log read但是要走一遍raft log,读涉及到磁盘IO,v3.1中引入了readIndex机制,它是非常轻量级的,开销较小,相比各个follower都转发给leader会导致leader负载较高,特别是expensive request场景,性能会急剧下降,leader的内存、cpu、网络带宽资源都很容易耗尽,readIndex机制的引入,使得每个follower节点都可以处理读请求,极大扩展提升了写性能。

    2021-02-16
    5
    31
  • 姜姜
    老师,文中有些地方不太明白:
    1, KVServer中的拦截器
    我认为它只是作为一个辅助的功能吧,用于实现一些观测功能。但对于一个普通的读请求,是否必须通过拦截器才能完成读取数据的操作?

    2, 文中“handler 首先会将上面描述的一系列拦截器串联成一个执行”
    这段话中,拦截器是一系列的,一系列是指会有多个拦截器吗?难道不是一个请求只注册一个拦截器吗,还能注册多个?为什么要注册多个?
    “串联成一个执行”,如何串联成一个?将多个拦截器串联成一个拦截器?

    3, 串行读与线性读
    这里我理解串行读是“非强一致性读”,线性读是“强一致性读”,对吗?
    而且这里的“串行”总让我想到“并行/串行”的概念,不知有关系吗?

    4, ReadIndex,committed index,applied index
    这几种索引底层实现是一样的吗,它们的数据结构是怎样的?是对同一份数据,分别建立不同的索引?又为什么建立这么多种索引?

    5,版本号
    您说是一个递增的全局ID, revision{2, 0},ID指的是2还是0? 版本号的格式是怎样的,另一个数字代表什么?

    6, bucket
    请问一个 bucket 相当于一整个 B+ tree 索引树吗?还是相当于 B+ tree 中一个节点?

    作者回复: 谢谢你的提问,我先简单快速回答下,后面不清楚的再写答疑文章深入解答
    问题1和2是gRPC拦截器相关知识我推荐你看下这篇文章https://zhuanlan.zhihu.com/p/80023990
    问题3你理解串行读是“非强一致性读”,线性读是“强一致性读”没问题,至于串行含义并非你想的那样,你可以参考下维基百科的定义, 09事务篇我也会介绍事务隔离中的串行化
    https://en.wikipedia.org/wiki/Serializability
    问题4 建议先去阅读下04 raft篇,它本值上就是一个uint64的索引,表示日志条目序号
    问题5,{2,0}={major,sub} 2是etcd mvcc事务版本号全局递增,0是事务内子版本号随修改操作递增(比如一个txn事务中多个put/delete操作,其会从0递增),07 mvcc会详细介绍
    问题6,一个bucket对应一个颗B+tree

    2021-01-26
    5
    18
  • 小军
    请问老师,当Readindex结束并等待本节点的状态机apply的时候,key又被最新的更新请求给更新了怎么办,这个时候读取到的value是不是又是旧值了

    作者回复: 线性读,读出来的值实际上是你发出读请求时间点的集群最新共识数据,在你读请求发出后,若耗时一定时间还未完成,在这过程中leader又收到了写请求更新了它, 的确你原来读出来的值相比最新的集群共识就是旧的,在实际应用中,我们一般会通过增加版本号检测识别此类问题,后面事务篇会详细和你介绍

    2021-01-26
    12
  • chapin
    没有基础,学习这个,可能会比较吃力。

    作者回复: 没关系的,可以先大概看一篇,了解整个流程,不懂什么地方可以等学完后面后,回过头来再看就非常亲切了,后面每节中都有etcd特性体验案例,建议你跟着我一起实际操作下,比如02你就先准备好环境,能用goreman快速启一个多节点集群,也可以自己直接二进制启动一个单节点集群,然后体验一下get,put命令,随着后面的学习你会越来越了解etcd

    2021-01-26
    8
  • jeffery
    干货太多需要慢慢消化!老师能把课程代码放到github上吗……谢谢老师

    作者回复: 嗯,不清楚的地方不要急,后面的每节会帮助你一个个解开疑问

    2021-01-22
    7
  • 站在树上的松鼠
    老师,下面这句话没有理解到,麻烦解答下呢,谢谢!
    在client 3.4之前的版本中,负载均衡算法有一个严重的Bug:如果第一个节点异常了,可能会导致你的client访问etcd server异常。
    (1)这里第一个节点怎么理解呢? 是指的负载均衡刚好选中的那个etcd server节点异常吗?
    (2)如果访问的节点异常了,是client库中会做重试机制,还是业务代码需要做重试呢?

    作者回复: 感谢超凡帮忙解答第一点,第二点取决于rpc方法,range clientv3库有重试策略,参考一下这个文件clientv3/retry.go

    2021-01-22
    3
    5
  • yayiyaya
    问答: etcd 在执行读请求过程中涉及磁盘 IO 吗?
    答: 涉及到磁盘, 当读请求从treeIndex获取到用户的 key 和相关版本号信息后,去查询value值时, 没有命中 buffer, 会从boltdb获取数据, 这个时候就涉及到了磁盘。

    作者回复: etcd启动的时候通过mmap将db文件映射到内存,会告诉内核预读文件,下一讲给了参考答案

    2021-02-04
    4
  • Want less
    当收到一个线性读请求时,它首先会从 Leader 获取集群最新的已提交的日志索引 (committed index)。
    所有的client请求不是应该都通过leader下发至follower吗?

    作者回复: 不是的哈,follower节点也可以处理读请求的,只是线性读时需要向leader发送readindex消息,然后确保本节点数据是最新的

    2021-01-27
    4
  • 于途
    如果你的 client 版本 <= 3.3,那么当你配置多个 endpoint 时,负载均衡算法仅会从中选择一个 IP 并创建一个连接(Pinned endpoint)

    请问,此句提到的负载均衡算法是否等同:随机选中某个IP?

    作者回复: 嗯,可以理解为随机,首先它会尝试连接所有etcd节点,连接建立后选择一个固定的长连接,其他关闭

    2021-01-22
    4
  • 范闲
    wal log里面会涉及到磁盘读写。lsm树,双memtable,都满了刷到磁盘,继续写memtable.

    作者回复: 读请求不涉及wal log,读流程中你可以看看不需要它,写请求会介绍,lsm树是leveldb使用的存储模型,etcd使用的是b+tree。

    2021-01-22
    2
    4
  • 七里
    boltdb怎么保证全局的revision呢

    作者回复: boltdb的key是revision,revision本身由etcd mvcc模块维护全局单调递增

    2021-01-26
    2
  • 写点啥呢
    另外还想问下唐老师,是否会有章节介绍下etcd集群管理和请求路由的原理,比如节点如何探活及增减,及像在线性读场景里,请求是否一定要通过已提交的quorum内节点处理还是任何节点都可以处理呢?

    作者回复: 好的,第一点,加餐篇计划增加集群成员管理等内容,第二点,任何follower节点都可以处理读请求,如果是线性读,它们都会向leader节点发出readindex请求,然后等待本节点数据赶上leader,如果一个follower节点io异常,数据落后多就可能超时

    2021-01-22
    2
  • 出卖灵魂的教练kerry
    老师,如果ReadIndex读过程中,流程4状态机迟迟不应用索引?或者流程5中,未能通知到读请求?这些情况会换节点读还是幂等重试呢?

    作者回复: 参考我上面的评论,超时后依赖客户端重试,3.4中round-robin负载均衡算法重试后就会选择另外一个节点

    2021-01-22
    2
    2
  • Alery
    请教一个问题,在treeIndex中查询key对应的版本号,这里是会返回当前key的所有版本号吗?

    作者回复: 嗯,每个key在treeIndex中有一个对应的数据结构keyIndex,它保存了所有版本号(若未压缩),07讲mvcc将详细介绍

    2021-01-26
    1
  • Nights Watch
    老师,请问下etcd是不是对IO读写延迟要求很高,最近发现磁盘IO性能下降时apiserver连不上etcd

    作者回复: 是的,可以看看03写请求分析,WAL和db文件都依赖磁盘IO性能

    2021-01-25
    1
  • 喵阁等
    通过goreman,快速安装etcd集群,提示“transport: http2Server.HandleStreams failed to read frame: read tcp 127.0.0.1:2379->127.0.0.1:47320: read: connection reset by peer”,是什么那里设置不对吗?

    作者回复: 看起来是正常错误,etcd master版本中我修复过,试试etcdctl get命令不报错吧

    2021-01-24
    1
  • Coder4
    ReadIndex其实没读懂,又查了下其他资料
    其实应该是写成read index,维持和commited index一致,就能明白了

    作者回复: 嗯,你这么说也有道理,感谢,希望其他读者看到你的评论能有所帮助,我是参考etcd raft消息和接口使用的大写

    2021-01-23
    1
  • no-one
    如果读之前follower节点的索引已经是最新的了,还会先去leader节点读readindex吗

    作者回复: 是的,follower节点是无法确认自己是否最新的,数据是leader向follower同步的

    2021-01-23
    1
  • 一步
    ETCD 集群中,每个节点都有 WAL 和状态机功能吗? WAL 不是 leader 节点才起作用的?

    作者回复: 是的,每个节点都有WAL, leader会向follower节点同步raft日志条目,日志条目中保存请求的命令,follower收到后会保存到wal中,此日志条目被提交后,各个节点应用它到状态机boltdb等中,后面两节会详细介绍,周一写请求原理,周三raft原理你看了后就非常清晰了。

    2021-01-22
    1
  • Geek_604077
    环境准备中踩坑日记
    我用的是etcd Version: 3.5.0版本
    1、需要将etcd解压文件夹下的bin文件目录设置到环境变量中,
    官网文档修改环境变量用的是export的方式,该方式只会在
    当前会话生效(难怪我打开别的终端窗口就执行不了etcd的
    命令)可以通过sudo vim ./bash_profile的方式添加
    全局才会生效
    2、文稿中的下载 goreman Procfile的文件需要做一点修改把
    “bin/etcd”改成“etcd”即可因为我们刚刚设置了全局的环境变

    3、etcdctl get hello --endpoints http://127.0.0.1:2379
    没有输出任何内容,这个人猜测是因为版本于老师版本不一致的原因
    我用官网快速开始文档教程动手试了试有输出正常的hello etcd的
    (以上是我在安装etcd踩的坑,因为我比较小白,贴出来印象深刻些,
    毕竟老师的课堂作业做不出来,也不想空着)

    2022-01-24
收起评论
56
返回
顶部