etcd 实战课
唐聪
腾讯云资深工程师,etcd 活跃贡献者
4279 人已学习
立即订阅
登录后,你可以任选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
登录|注册
开通超级会员可免费学习本课程,还可解锁海量内容免费学特权。

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

你好,我是唐聪。
在上一节课里,我通过分析 etcd 的一个读请求执行流程,给你介绍了 etcd 的基础架构,让你初步了解了在 etcd 的读请求流程中,各个模块是如何紧密协作,执行查询语句,返回数据给 client。
那么 etcd 一个写请求执行流程又是怎样的呢?在执行写请求过程中,如果进程 crash 了,如何保证数据不丢、命令不重复执行呢?
今天我就和你聊聊 etcd 写过程中是如何解决这些问题的。希望通过这节课,让你了解一个 key-value 写入的原理,对 etcd 的基础架构中涉及写请求相关的模块有一定的理解,同时能触类旁通,当你在软件项目开发过程中遇到类似数据安全、幂等性等问题时,能设计出良好的方案解决它。

整体架构

为了让你能够更直观地理解 etcd 的写请求流程,我在如上的架构图中,用序号标识了下面的一个 put hello 为 world 的写请求的简要执行流程,帮助你从整体上快速了解一个写请求的全貌。
etcdctl put hello world --endpoints http://127.0.0.1:2379
OK
首先 client 端通过负载均衡算法选择一个 etcd 节点,发起 gRPC 调用。然后 etcd 节点收到请求后经过 gRPC 拦截器、Quota 模块后,进入 KVServer 模块,KVServer 模块向 Raft 模块提交一个提案,提案内容为“大家好,请使用 put 方法执行一个 key 为 hello,value 为 world 的命令”。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/1000字
划线
笔记
复制
03 | 基础架构:etcd一个写请求是如何执行的?
04 | Raft协议:etcd如何实现高可用、数据强一致的?
08 | Watch:如何高效获取数据变化通知?
12 | 一致性:为什么基于Raft实现的etcd还会出现数据不一致?
16 | 性能及稳定性(上):如何优化及扩展etcd性能?
21 | 分布式锁:为什么基于etcd实现分布式锁比Redis锁更安全?
开通超级会员免费畅看本课程
开通会员
该文章仅可免费阅读部分内容,如需阅读完整文章,请开通超级会员或单独购买本课程。
登录 后留言

精选留言(39)

  • 唐聪
    之前修复的存在3年多的不一致bug就是跟本节介绍的写请求幂等性有关,在每讲中,我提及的bug,特性缺点,大部分都是我之前踩过的坑,这些经验希望能帮助大家提前避免不必要的线上问题
    2021-01-26
    1
    41
  • Index
    之前研究一段时间的etcd的源码,看的七七八八,现在再看这篇文章把之前的很多疑问都解答了,太棒了,etcd是个很优秀的项目,能把这么多的技术点融合在一起,实在是一个很好的开源学习项目。老师有空可以开直播,多聊聊etcd中涉及的技术点的一些学习,从源头上把知识融汇贯通,这样的学习真是酣畅淋漓

    作者回复: 好的,谢谢你的认可,一起学习加油

    2021-01-26
    10
  • TS.乔
    希望在后面多加一下具体设计思路,以及特性取舍的东西

    作者回复: 嗯,谢谢你的建议,篇幅本身比较长就没继续扩展了,比如读写原理中,treeindex为什么用b-tree而不是其他数据结构,为什么使用boltdb而不是基于lsm树的leveldb等,后面答疑和其他讲我将适当和大家一起讨论

    2021-01-26
    2
    5
  • 于途
    1)首先 boltdb key 是版本号,put/delete 操作时,都会基于当前版本号递增生成新的版本号,因此属于顺序写入,可以调整 boltdb 的 bucket.FillPercent 参数,使每个 page 填充更多数据,减少 page 的分裂次数并降低db空间。 此处的page 和 降低db空间不是很理解,劳烦老师解惑!

    2)关于版本号(revision)的理解:假定全局版本号currentRevision=2,第一次执行 put hello world1,那么版本号为:hello:revision{2,0};第二次执行 put hello world2,此时版本号为:hello:revision{3,1};第3次执行 put hello world3,此时版本号为:hello:revision{4,2}。 不知理解是否有偏差?

    作者回复: 第一个问题,10 boltdb篇会帮助你深入解答第1个问题,稍等
    第二个问题,{2,0}={major,sub} 2是etcd mvcc事务版本号全局递增,0是事务内子版本号随修改操作递增(比如一个txn事务中多个put/delete操作,其会从0递增),因此第二次执行put hello world2的时候版本号应是{3,0}, 07 mvcc会详细介绍,明天更新

    2021-01-28
    4
  • 七里
    幂等部分的“原子性事务”如何实现的?

    作者回复: 就是key-value数据与consistent index在同一个boltdb事务中更新,boltdb后面会再单独介绍

    2021-01-26
    2
    4
  • jeffery
    原理讲的透彻、为啥applied index超过了 5000,返回一个"etcdserver: too many requests"错误给 client。raft源码定义的最大值吗?谢谢老师

    作者回复: 谢谢,这个限速不是raft模块做的,raft是个单独共识算法库,是etcd server使用raft的时候,基于raft告知的committed index,本身apply模块的applied index做的限速,默认写死了5000

    2021-01-26
    4
  • 憨憨
    讲的真好,干货十足

    作者回复: 感谢认可😊

    2021-02-04
    3
  • 云原生工程师
    文章有点长,但读起来层层递进,有很大收获,发现之前自己所了解的还真不全面,填补了之前的一些空白面,期待后面的精彩内容
    2021-01-26
    3
  • 范闲
    会有影响。
    1.如果读写请求都落到bucket buffer上,bucketbuffer需要做锁处理。
    2.如果读写请求都落到boltdb上,db上的数据是从磁盘加载,同bucket buffer相比性能会下降一个数量级。
    3.如果既落了bucket buffer,又落到了boltdb上。那么性能受到的影响介于1-2之间。
    2021-01-25
    4
    3
  • types
    1. consistent index具体是如何保存的,如何实现跟具体操作实现原子性提交的
    2. readIndex跟consistent index儒者WAL index什么关系? ReadIndex一定要处于commited吗?
    2021-03-02
    2
  • Geek_5a8405
    从节点收到Propose请求后会写wal日志吗?那如果最终并没有一半的节点成功响应,那已经写入wal的从节点怎么处理呢?

    作者回复: 赞,阅读过程中有深入思考,你可以看看04节raft,其中思考题与你说的类似,05有参考答案

    2021-02-10
    2
  • kingstone
    请问revision如果超出了上限,revision会如何接着生成?

    作者回复: 好问题,目前etcd没处理这种情况,它的类似是int64,最大值9223372036854775807,看起来是很难达到上限的

    2021-01-26
    2
  • 励研冰
    这篇仔细读了好几遍每次都有不一样的收获跟理解,被很多设计细节跟思路所折服,最后整理了下发现etcd的写流程居然跟mysql中的设计有异曲同工之妙,比如mysql中的redolog,binlog,changebuff,内存缓存,事物合并提交等…….,最后有一个不明白的点是为什么在boltdb提交事物的时候不是用key的mod_revision而是要重新生成新的版本号
    2021-11-04
    1
    1
  • 花晨少年
    etcd 通过引入一个 consistent index 的字段,来存储系统当前已经执行过的日志条目索引,实现幂等性。
    -----
    consistent index 是一个全局的值吗,单调递增的?还是主要有raft日志应用到状态机,就会存储当前consistent index值吗,判断日志使用已经执行过,是需要进行key查找所有存储的consistent index值吗

    作者回复: 对,是一个全局单调递增的值,在boltdb中有一个key维护它,etcdserver应用已提交的raft日志条目到状态机时,会查询此日志条目的索引是否大于consistent index,如果大于则同key-value等数据在同boltdb事务中更新它,否则说明此日志条目已执行过。

    2021-04-17
    1
  • 恰同学少年。
    感觉不太会。
    1. client有负载均衡不会有很多请求都直接到主?
    2. v3支持多路复用(这样到主链接数应该不会太多)
    3. 线性读请求只会向主发获取ReadIndex的请求,还挺轻量的。
    4. boltdb只有启动时会加载db文件并映射到mmap,内存够就不会有磁盘IO,所以影响也不大。
    2021-02-20
    1
  • 意志
    "其次 etcd 通过合并多个写事务请求,通常情况下,是异步机制定时(默认每隔 100ms)将批量事务一次性提交(pending 事务过多才会触发同步提交), 从而大大提高吞吐量,对应上面简易写事务图的流程三。"

    你好,异步提交的事务,突然crash的话,如果保证安全写入磁盘呢?是boltdb有什么机制保证吗?我在boltdb那个章节没有看到相关内容,就此请教一下。
    2021-02-20
    2
    1
  • 于途
    etcd 默认超时时间是 7 秒(5 秒磁盘 IO 延时 +2*1 秒竞选超时时间)

    老师,“竞选超时时间”具体指的是什么?还有磁盘IO延时要怎么理解比较贴切?
    2021-01-28
    1
  • 一步
    这里 db 配额(Quota)的限制哪个地方的大小的? 为什么会有这样的限制呢? 这个限制是 boltdb 全部数据 持久化后的文件大小吗?

    作者回复: boltdb的db文件,你可以在etcd的数据目录snap目录下看到有个名为db的文件,实践篇我会介绍db文件过大又哪些问题,etcd定位就是个小型的关键元数据存储

    2021-01-26
    1
  • 残天噬魂
    老师,这个Quota 模块是干什么用的?
    2021-12-31
  • Adam
    老师,假如我的etcd 集群部署在k8s中,通过lb 的方式暴露服务出来,集群外的apisix 通过slb 地址去访问etcd 服务是不是也是负载均衡的方式?
    2021-11-17
收起评论
39
返回
顶部