名词解释
先解释下etcd中提供的LinearizableRead是什么意思。线性化(Linearizable)是介于严格一致性和顺序一致性之间的一种一致性级别。Linearizable假设所有的操作都有会被排序,并且确保后一个操作可以看到前一个操作的结果,同时要求所有的server都能达成这个共识。
举个更加具体的例子,如果我们有一个client,三个server;client先write(x, 9),再read(x),一定会得到结果9,不管write和read操作被发送到了哪个server上。
而这种线性一致,正是依赖raft的ReadIndex
去实现的。etcd调用ReadIndex()
时,会带上一个唯一ID,然后等待node.Ready()
返回并与这个唯一id匹配上,然后才可以读数据。这个过程中又做了一些优化。我们看看etcd的具体实现:
RaftNode:etcd对raft模块的封装
状态机:etcd-raft上层的应用
前台两个channel
前台的同步逻辑非常简单,其会调用LinearizableReadNotify
并等待这个函数返回后再读数据。可以看到重点是往readwaitc
发信号,再等待readNotifier
的信号。
func (s *EtcdServer) LinearizableReadNotify(ctx context.Context) error {
return s.linearizableReadNotify(ctx)
}
func (s *EtcdServer) linearizableReadNotify(ctx context.Context) error {
s.readMu.RLock()
nc := s.readNotifier
s.readMu.RUnlock()
// 往readwaitc发信号
// 通知readwaitc有读请求进来;readwaitc容量只有1,所以在并发的情况下,其他的协程会命中default分支,这样可以避免重复提醒,也相当于将多个读合并成一个读
select {
case s.readwaitc