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

最低0.47元/天 解锁文章
1927

被折叠的 条评论
为什么被折叠?



