1
2
4
1
博客/.../

TiDB Raft 协议学习研究

 北南南北  发表于  2026-03-10

TiDB Raft 协议学习研究

摘要

本文深入探讨了 TiDB 核心存储引擎 TiKV 中 Raft 协议的实现原理、关键优化及其对系统一致性和可用性的保障。详细分析了 Multi-Raft 机制如何实现数据分片和负载均衡,以及 ReadIndex、Lease Read 和 Follower Read 等读取优化技术如何提升系统性能并保证强一致性。此外,还介绍了 Joint Consensus 等高级优化在 TiKV 中的应用,旨在全面理解 TiDB 分布式架构的底层共识机制。

1. Raft 协议基础与 TiKV 中的应用

Raft 是一种易于理解和实现的分布式一致性算法,旨在解决分布式系统中的数据一致性、高可用性和容错性问题。在 TiDB 的架构中,TiKV 作为其分布式事务型键值存储引擎,广泛采用了 Raft 协议来管理数据的复制和状态机的同步。每个数据分片(Region)都作为一个独立的 Raft Group 运行,拥有自己的 Leader 和 Follower 节点。Leader 负责处理所有的写入请求,并将日志复制到 Follower 节点,确保数据的强一致性。当多数节点确认日志条目已写入其日志后,Leader 才会提交该日志,并将其应用到状态机中。

2. Multi-Raft 机制

TiKV 引入了 Multi-Raft 机制,这意味着在单个 TiKV 节点上可以管理多个 Raft 共识组。这一设计是 TiKV 实现数据分片和水平扩展的关键。具体而言,TiKV 将整个键空间划分为一系列 Region,每个 Region 负责存储一个连续的键范围,并对应一个独立的 Raft Group。这种设计带来了显著的优势:

  • 数据分片与负载均衡:通过将数据分散到多个 Region,TiKV 能够将负载均匀地分布到集群中的不同节点上。当某个 Region 的数据量或访问压力过大时,TiKV 可以对其进行**分裂(Split)操作,将其拆分为两个或多个新的 Region。反之,当相邻的两个 Region 数据量较小时,也可以进行合并(Merge)**操作,以减少管理开销。这种动态的 Region 管理机制使得 TiKV 能够灵活地适应数据增长和负载变化。
  • 高可用性与容错:每个 Raft Group 独立运行,即使集群中部分节点发生故障,只要多数派节点仍然可用,对应的 Raft Group 就能继续提供服务,从而保证了系统的高可用性。

在 Multi-Raft 架构中,TiKV 在 Raft 协议之上增加了一个管理层,以整体协调和驱动这些 Raft Group。TiKV 使用**事件循环(Event Loop)**机制来批量驱动所有的 Raft 状态机。每隔固定的时间间隔(例如 1000ms),事件循环会轮询所有的 Raft Group,处理它们的 Raft Ready 状态。这包括:

  1. 批量持久化:遍历所有处于 Ready 状态的 Raft Group,使用 RocksDB 的 WriteBatch 机制将所有待写入的数据批量持久化到存储引擎中。这种批量写入的方式显著减少了磁盘 I/O 操作,提高了写入吞吐量。
  2. 消息发送:在数据成功持久化后,Leader 会向其 Follower 节点发送 Raft 消息(如心跳、日志复制请求)。TiKV 会复用节点间的网络连接,以减少连接建立和维护的开销。
  3. 日志应用:将已提交的日志条目应用到状态机中,更新数据状态。

3. Raft 读取优化

在分布式系统中,读取操作的性能对用户体验至关重要。Raft 协议为了保证强一致性,通常要求读取操作也经过 Leader 的确认。然而,直接通过 Raft 日志进行读取会带来较大的性能开销。TiKV 针对读取操作进行了多种优化,以在保证强一致性的前提下提升读取性能。

3.1 Raft Log Read

Raft Log Read 是最直接的读取方式,它将读取请求也作为一个 Raft 日志条目提交。Leader 接收到读取请求后,会将其追加到本地日志中,并复制给 Follower 节点。只有当该日志条目被多数节点确认并提交后,Leader 才会从状态机中执行读取操作并返回结果。这种方式能够保证强一致性,但由于每个读取请求都需要经过完整的 Raft 协议流程(包括日志复制和提交),其性能开销巨大,吞吐量较低,因此在实际生产环境中很少采用。

3.2 ReadIndex Read

为了改善 Raft Log Read 的性能瓶颈,Raft 协议提出了 ReadIndex Read 优化。其核心思想是 Leader 在处理读取请求之前,首先要确认自己仍然是有效的 Leader,并且其状态机已经包含了最新的已提交日志。具体流程如下:

  1. 记录提交索引:Leader 收到读取请求后,记录当前的已提交日志索引(commit index)作为 ReadIndex
  2. 确认 Leader 身份:Leader 向集群中的所有 Follower 节点发送一次心跳消息。当收到多数 Follower 节点的响应后,Leader 即可确认自身仍然是有效的 Leader,且其 commit index 是最新的。
  3. 等待状态机同步:Leader 等待其本地状态机应用日志,直到其 applied index 达到或超过 ReadIndex。这确保了 Leader 的状态机是最新的,包含了所有在 ReadIndex 之前提交的日志。
  4. 执行读取:一旦状态机同步完成,Leader 即可安全地执行读取请求并返回结果。

ReadIndex Read 避免了将读取请求写入 Raft 日志,从而减少了写入开销。虽然仍然需要一次与多数节点的 RPC 交互来确认 Leader 身份,但相比 Raft Log Read,其性能有了显著提升,并能保证线性一致性

3.3 Lease Read

Lease Read 是 TiKV 采用的一种更进一步的读取优化,它在 ReadIndex Read 的基础上进一步减少了网络交互,显著提升了读取性能。Lease Read 利用了 Leader 租约(Lease)的概念。当 Leader 成功地与多数节点通信后,它会获得一个在一定时间内有效的租约。在租约有效期内,Leader 可以直接处理读取请求,而无需再次与 Follower 节点进行 RPC 交互来确认 Leader 身份。

TiKV 对 Raft 论文中提出的 Lease Read 进行了优化:

  • 租约更新机制:TiKV 并没有通过周期性的心跳来更新租约,而是通过写操作来更新。当 Leader 接收到写请求并将其提交到 Raft 日志后,它会更新自己的租约。由于所有的写操作都必须经过 Leader 并复制到多数节点,因此通过写操作更新租约能够自然地反映 Leader 的活跃状态。
  • 安全性保障:Lease Read 的安全性依赖于**选举超时时间(election timeout)时钟漂移边界(clock drift bound)**的精确控制。TiKV 确保在发生网络分区(脑裂)的情况下,旧 Leader 的租约在新 Leader 被选举出来之前一定会过期。例如,如果选举超时时间为 10 秒,TiKV 会将租约有效期设置为小于 9 秒,以保证在最坏情况下,旧 Leader 的租约在新 Leader 产生前失效,从而避免了脏读。

通过 Lease Read,TiKV 能够在租约期内以极低的延迟提供读取服务,极大地提高了读取吞吐量和系统性能,同时依然保证了强一致性

3.4 Follower Read

Follower Read 是 TiKV 引入的另一项重要读取优化,旨在进一步分担 Leader 的读取压力,提高系统的整体读取吞吐量。传统 Raft 协议中,所有读取请求都必须由 Leader 处理。但在某些场景下,允许 Follower 节点处理读取请求可以显著提升性能。

Follower Read 的实现并非简单地让 Follower 直接提供读取服务,因为这可能导致读取到过期数据。为了保证一致性,Follower Read 结合了 ReadIndex 机制:

  1. 获取最新提交索引:当 Follower 节点收到读取请求时,它会首先通过 Raft ReadIndex 协议与当前的 Leader 节点进行一次交互,获取 Leader 最新的 commit index
  2. 等待本地同步:Follower 节点等待其本地状态机应用日志,直到其 applied index 达到或超过从 Leader 获取的 commit index
  3. 执行读取:一旦本地状态机同步到最新状态,Follower 即可安全地执行读取请求并返回结果。

Follower Read 能够有效地提高系统的读取吞吐量,尤其是在读多写少的场景下,可以显著降低 Leader 的负载。结合 TiDB 的快照隔离(Snapshot Isolation)特性,Follower Read 能够保证单行数据读取的线性一致性,为用户提供高性能且一致的读取体验。

4. Raft 高级优化

除了上述核心机制和读取优化外,TiKV 还对 Raft 协议进行了多项高级优化,以进一步提升其在分布式环境中的性能、可用性和可管理性。

4.1 Joint Consensus (联合共识)

Joint Consensus 是一种用于集群成员变更的 Raft 优化方案。在分布式系统中,动态地添加或移除节点是一项常见的操作。传统的 Raft 成员变更可能需要分多步进行,且在某些步骤中可能存在集群不可用的风险。Joint Consensus 解决了这一问题。

其核心思想是,在成员变更过程中,集群会进入一个联合配置(Joint Configuration)状态。在这个状态下,集群同时维护新旧两种配置。只有当新旧两种配置都达到多数派时,日志才能被提交。一旦联合配置下的日志被提交,集群就可以安全地切换到新的配置。这种方式避免了在成员变更过程中集群不可用的风险,并允许任意的成员组变更,从而为 TiKV 提供了更强的扩展性管理灵活性

4.2 批量处理 (Batching) 与 流水线 (Pipelining)

为了在高吞吐量场景下提升性能,TiKV 广泛采用了**批量处理(Batching)流水线(Pipelining)**技术来优化 Raft 协议的日志复制和存储引擎的写入。

  • 批量处理:将多个小的 Raft 日志条目或写入请求合并成一个更大的批次进行处理。这减少了网络 RPC 的次数和磁盘 I/O 操作,从而降低了系统开销,提高了整体吞吐量。例如,TiKV 在将数据写入 RocksDB 时,会使用 WriteBatch 将多个写入操作合并成一个事务进行提交。
  • 流水线:允许 Leader 在收到前一个日志复制请求的响应之前,就发送下一个日志复制请求。这充分利用了网络带宽,减少了等待时间,提高了日志复制的效率和吞吐量。

这些优化共同作用,使得 TiKV 能够在高并发和大数据量的场景下保持出色的性能。

4.3 异步写入 (Asynchronous Write)

在 Raft 协议中,日志的持久化是保证数据安全的关键环节。传统的同步写入方式可能会阻塞 Raft 状态机的推进,尤其是在磁盘 I/O 性能成为瓶颈时。TiKV 采用了异步写入的策略来优化日志持久化过程。

异步写入意味着 Leader 在将日志复制给 Follower 的同时,可以将日志写入本地磁盘的操作异步化。Leader 不会等待本地磁盘写入完成才发送下一个日志复制请求,而是将写入任务提交给后台线程处理。这种方式可以减少写入延迟提高 Raft 日志复制的效率,并避免因磁盘 I/O 阻塞而导致的系统性能波动,尤其是在面对突发写入高峰(QPS 尖峰)时,能够更好地平滑负载。

5. 总结

TiDB 的 Raft 协议实现是其分布式架构的基石,通过一系列精巧的设计和优化,TiKV 成功地构建了一个高性能、高可用、强一致的分布式存储系统。Multi-Raft 机制实现了数据的水平扩展和负载均衡;ReadIndex、Lease Read 和 Follower Read 等读取优化在保证强一致性的前提下显著提升了读取性能;而 Joint Consensus、批量处理、流水线和异步写入等高级优化则进一步增强了系统的可用性、吞吐量和稳定性。这些技术的综合应用,使得 TiDB 能够满足大规模企业级应用对数据存储的严苛要求。

1
2
4
1

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论