作者回复: 非常好的问题,我个人认为主要还是性能因素,我记得etcd v2早期的时候如果你指定线性读/共识读,它就是直接转发给leader的。后来在etcd v3.0中实现了raft log read但是要走一遍raft log,读涉及到磁盘IO,v3.1中引入了readIndex机制,它是非常轻量级的,开销较小,相比各个follower都转发给leader会导致leader负载较高,特别是expensive request场景,性能会急剧下降,leader的内存、cpu、网络带宽资源都很容易耗尽,readIndex机制的引入,使得每个follower节点都可以处理读请求,极大扩展提升了写性能。
作者回复: 谢谢你的提问,我先简单快速回答下,后面不清楚的再写答疑文章深入解答 问题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
作者回复: 线性读,读出来的值实际上是你发出读请求时间点的集群最新共识数据,在你读请求发出后,若耗时一定时间还未完成,在这过程中leader又收到了写请求更新了它, 的确你原来读出来的值相比最新的集群共识就是旧的,在实际应用中,我们一般会通过增加版本号检测识别此类问题,后面事务篇会详细和你介绍
作者回复: 没关系的,可以先大概看一篇,了解整个流程,不懂什么地方可以等学完后面后,回过头来再看就非常亲切了,后面每节中都有etcd特性体验案例,建议你跟着我一起实际操作下,比如02你就先准备好环境,能用goreman快速启一个多节点集群,也可以自己直接二进制启动一个单节点集群,然后体验一下get,put命令,随着后面的学习你会越来越了解etcd
作者回复: 感谢超凡帮忙解答第一点,第二点取决于rpc方法,range clientv3库有重试策略,参考一下这个文件clientv3/retry.go
作者回复: 嗯,不清楚的地方不要急,后面的每节会帮助你一个个解开疑问
作者回复: 不是的哈,follower节点也可以处理读请求的,只是线性读时需要向leader发送readindex消息,然后确保本节点数据是最新的
作者回复: 嗯,每个key在treeIndex中有一个对应的数据结构keyIndex,它保存了所有版本号(若未压缩),07讲mvcc将详细介绍
作者回复: etcd启动的时候通过mmap将db文件映射到内存,会告诉内核预读文件,下一讲给了参考答案
作者回复: 嗯,可以理解为随机,首先它会尝试连接所有etcd节点,连接建立后选择一个固定的长连接,其他关闭