![化茧成蝶:Go在FreeWheel服务化中的实践](https://wfqqreader-1252317822.image.myqcloud.com/cover/26/927026/b_927026.jpg)
![](https://epubservercos.yuewen.com/58535E/10210293804691401/epubprivate/OEBPS/Images/1.png?sign=1739672871-hQNUNXPU5390TFOWHnvay2RuwCxJeEV7-0-1ff550949ba6d7fd34288df4915750e0)
ETCD对写请求的处理
前文简要的梳理了Raft协议在ETCD节点中的实现和数据流。本节以ETCD3中的一次普通的数据写(V2/V3 API)为例介绍ETCD中存储系统的设计和实现。注意本节之所以只关注“写”操作,是因为读操作直接访问本地存储,不涉及复杂的分布式决策流程。V3 API中引入了MVCC存储,本质上与V2中的处理流程是一样的,区别在于最终执行时针对的本地存储不同(基于V3.1.8源码)。
先看V3 API中的Put操作的实现,Fig 3.1为V3中Put操作的gRPC Handler定义。
Fig 3.1 V3 Put的gRPC Handler
![](https://epubservercos.yuewen.com/58535E/10210293804691401/epubprivate/OEBPS/Images/figure_0061_0001.jpg?sign=1739672871-g8tPEwthifWICvXMjoJVTiLhU6xYcDXK-0-853da76d721970ce72fc37cc67619ef6)
这里的KVServer是一个Interface,具体的KVServer.Put实现在ETCDServer中。
Fig 3.2 V3 API Put操作的实现
![](https://epubservercos.yuewen.com/58535E/10210293804691401/epubprivate/OEBPS/Images/figure_0061_0002.jpg?sign=1739672871-jaxdaqY1eB8k8OjOncIrHVr9Y0z0RcJD-0-44411f76a8f335ec4f0aad633b725ddc)
这里有两个比较有意思的点:
· V3 Put消息(指令)传入Raft状态机后是怎么被执行的?
· Raft状态机是一个分布式的一步过程,客户端访问V3 API时如何实现等待分布式计算的结果?
先看V3 Put指令在Raft状态机的执行过程。在ETCD中Raft状态机是对每个消息进行“协商”的过程,这个过程其实是不关注其具体内容的,因此这里提到的“执行”的范畴,实际上是消息已经通过分布式节点协商(Committed),要在本地存储中执行(Apply)的过程。
Fig 3.3 applyEntryNormal中执行V3指令
![](https://epubservercos.yuewen.com/58535E/10210293804691401/epubprivate/OEBPS/Images/figure_0062_0001.jpg?sign=1739672871-2rL2y3AJqSFA4LEasoi02e8dHf1WNbwc-0-cc2eb06a364cdbec6e0201d66eabcc84)
值得一提的是,ETCD中采用一种有趣的方式来实现客户端等待异步任务的策略,客户端请求注册一个Waiter并监听这个Waiter对应的一个Channel,客户端会一直阻塞,直到这个Waiter被触发或超时。
V2指令的执行过程基本类似,Fig 3.4为V2 API一次Set操作的gRPC接口定义。
Fig 3.4 V2 Set操作gRPC Handler
![](https://epubservercos.yuewen.com/58535E/10210293804691401/epubprivate/OEBPS/Images/figure_0062_0002.jpg?sign=1739672871-QTVJRvcOZfmTS2YQcRvf2LQism717XEK-0-1bda948c02a6b19cf6c27940cf282733)
决策并提交指令之后,就需要在状态机中执行并修改内存数据库的状态。
Fig 3.5 applyEntryNormal中执行V2指令
![](https://epubservercos.yuewen.com/58535E/10210293804691401/epubprivate/OEBPS/Images/figure_0063_0001.jpg?sign=1739672871-GTseUtK0Dmm84hGDcmHH9zGZmmhi07PX-0-80c0a8dcf58ad026f33b841ce8591e64)