【ETCD】【源码阅读】深入解析 ETCD 线性一致性读请求处理流程(二)

在这里插入图片描述
本篇主要介绍ETCD如何确保在进行线性化读取时,集群中的所有节点已经达成一致。已经如何从leader节点获取到commitedIndex的具体源码。
为了完成这样功能,ETCD主要使用以下方法来保证:
linearizableReadNotify 方法: 用于等待并通知线性化读取的操作。它确保读取操作是线性化的,即在获取数据之前,集群中的节点达成一致。具体来说,它会等待读取状态的通知,保证在开始读取数据前所有相关节点已经同意执行该操作。
linearizableReadLoop: 方法通过一个无限循环,持续处理线性化读取请求,确保所有的读取请求都满足一致性要求。它依赖于 Raft 协议的确认索引来确保读取操作的顺序一致,并通过通知机制将读取请求解除阻塞。方法涉及了 Leader 节点变更的监控、索引确认的等待、追踪记录等多个步骤,确保系统在分布式环境中能够正确、高效地处理读取请求。
requestCurrentIndex: 通过发送 ReadIndex 请求并监听不同的事件,等待 Raft 集群中的响应。在此过程中,它会处理各种边界情况,例如 Leader 变更、首次提交、超时、重试等。方法中使用了多个定时器来控制请求超时和重试,同时保证了请求的可靠性和一致性。

一、linearizableReadNotify 方法详解

我们来一步步解析这段源码,linearizableReadNotifyEtcdServer 结构体的方法,用于通知进行线性化读取(Linearizable Read)操作的进程。

1. 方法签名与功能概述

func (s *EtcdServer) linearizableReadNotify(ctx context.Context) error
  • 功能:该方法用于等待并通知线性化读取的操作。它确保读取操作是线性化的,即在获取数据之前,集群中的节点达成一致。具体来说,它会等待读取状态的通知,保证在开始读取数据前所有相关节点已经同意执行该操作。

  • 参数

    • ctx context.Context:上下文,管理方法的生命周期,处理超时、取消等。
  • 返回值

    • error:返回操作中的错误,如超时、取消或停止等。

2. 读取互斥锁并获取读取通知器

s.readMu.RLock()
nc := s.readNotifier
s.readMu.RUnlock()
  • 作用:通过 s.readMu.RLock() 获取读锁,防止在读取 readNotifier 时发生并发问题。这里是读取共享变量 s.readNotifier,而 s.readMu 是一个 读写锁(RWMutex),允许多个线程并发读取。

    • s.readNotifier 是用于同步读取操作的通知器,保存了相关状态和错误信息。
  • RLock() 表示获取读锁,多个读操作可以并发执行,不会阻塞其它读操作。

  • RUnlock() 释放读锁。

3. 发送通知信号

// signal linearizable loop for current notify if it hasn't been already
select {
   
   
case s.readwaitc <- struct{
   
   }{
   
   }:
default:
}
  • 作用:通过 select 语句发送一个信号给 s.readwaitc 通道,通知正在等待的线性化读取操作。如果信号已经被发送(即 s.readwaitc 通道已满),则不再发送,避免重复通知。
    • s.readwaitc 是一个用于通知的通道,通常是另一个协程等待的通道,表示线性化读取可以继续。

4. 等待读取状态的通知

// wait for read state notification
select {
   
   
case <-nc.c:
    return nc.err
case <-ctx.Done():
    return ctx.Err()
case <-s.done:
    return ErrStopped
}
  • 作用:接下来的 select 语句用于等待来自不同源的通知:
    • <-nc.c:等待来自 nc.c 通道的信号。这是线性化读取通知器的通知通道,表示读取操作可以继续执行。如果成功接收到通知,会返回 nc.err,这是读取过程中可能发生的错误。
    • <-ctx.Done():如果上下文(ctx)已经被取消(例如超时或手动取消),则返回 ctx.Err() 错误,表示操作被取消。
    • <-s.done:如果服务器被停止(s.done 通道被关闭),则返回 ErrStopped 错误,表示服务已停止,不再继续操作。

关键点

  • readMu 读锁:用于保护对 readNotifier 的并发访问。
  • 线性化通知:通过 s.readwaitc 通道通知其它协程,保证线性化读取。
  • 错误处理:通过 select 语句处理多个可能的终止条件:读取完成、上下文取消、服务停止等。

二、linearizableReadLoop方法详解

我们来一步步解析这段源码,linearizableReadLoopEtcdServer 结构体的方法,用于执行线性化读取操作。这是一个关键的操作,确保读取操作能够在分布式系统中得到一致性保证。下面将逐行分析该方法的实现。


1. 方法签名与功能概述

func (s *EtcdServer) linearizableReadLoop()
  • 功能:这个方法是一个无限循环(for),用于执行线性化读取操作。它会不断监测集群状态,确保读取操作满足线性化一致性,即读取到的值与集群的写入状态是一致的。
  • 无参数,无返回值:该方法不接受参数,并且没有返回值,表明它是一个长期运行的后台进程。

2. 开始无限循环

for {
   
   
  • 作用:方法内部是一个无限循环,意味着它会持续运行直到被显式停止(通过 return 或外部条件)。

3. 生成请求ID与获取 Leader 变更通知

requestId := s.reqIDGen.Next()
leaderChangedNotifier := s.LeaderChangedNotify()
  • 作用
    • requestId := s.reqIDGen.Next():生成一个新的请求 ID,用于标识当前的线性化读取请求。
    • leaderChangedNotifier := s.LeaderChangedNotify():获取一个通知器,表示集群中的 Leader 节点变更。如果 Leader 发生变动,读取操作可能需要重新开始。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值