diff --git a/follower-read.md b/follower-read.md index b21d93278ee0..93264e9e9e9c 100644 --- a/follower-read.md +++ b/follower-read.md @@ -6,15 +6,26 @@ aliases: ['/docs-cn/dev/follower-read/','/docs-cn/dev/reference/performance/foll # Follower Read -当系统中存在读取热点 Region 导致 leader 资源紧张成为整个系统读取瓶颈时,启用 Follower Read 功能可明显降低 leader 的负担,并且通过在多个 follower 之间均衡负载,显著地提升整体系统的吞吐能力。本文主要介绍 Follower Read 的使用方法与实现机制。 +在 TiDB 中,为了保证高可用和数据安全,TiKV 会为每个 Region 保存多个副本,其中一个为 leader,其余为 follower。默认情况下,所有读写请求都由 leader 处理。Follower Read 功能允许在保持强一致性的前提下,从 Region 的 follower 副本读取数据,从而分担 leader 的读取压力,提升集群整体的读吞吐量。 -## 概述 +在执行 Follower Read 时,TiDB 会根据拓扑信息选择合适的副本。具体来说,TiDB 使用 `zone` label 判断一个副本是否为本地副本:当 TiDB 与目标 TiKV 的 `zone` label 相同时,TiDB 认为该副本是本地副本。更多信息可参考[通过拓扑 label 进行副本调度](schedule-replicas-by-topology-labels.md)。 -Follower Read 功能是指在强一致性读的前提下使用 Region 的 follower 副本来承载数据读取的任务,从而提升 TiDB 集群的吞吐能力并降低 leader 负载。Follower Read 包含一系列将 TiKV 读取负载从 Region 的 leader 副本上 offload 到 follower 副本的负载均衡机制。TiKV 的 Follower Read 可以保证数据读取的一致性,可以为用户提供强一致的数据读取能力。 +通过让 follower 参与数据读取,Follower Read 可以实现以下目标: + +- 分散读热点,减轻 leader 负载。 +- 在多可用区或多机房部署中,优先读取本地副本以减少跨区流量。 + +## 适用场景 + +Follower Read 适用于以下场景: + +- 读请求量大、存在明显读热点的业务。 +- 多可用区部署中,希望优先读取本地副本以节省带宽的场景。 +- 在读写分离架构下,希望进一步提升集群整体读性能的场景。 > **注意:** > -> 为了获得强一致读取的能力,在当前的实现中,follower 节点需要向 leader 节点询问当前的执行进度(即 `ReadIndex`),这会产生一次额外的网络请求开销,因此目前 Follower Read 的主要优势是将集群中的读请求与写请求隔离开,并提升整体的读吞吐量。 +> 为确保读取结果的强一致性,Follower Read 在读取前需要与 leader 通信以确认当前的提交进度(即执行 Raft `ReadIndex` 操作),该过程会带来一次额外的网络交互。因此,当业务中存在大量读请求或需要读写隔离时,Follower Read 的效果最为显著;但对于低延迟的单次查询,性能提升可能不明显。 ## 使用方式 @@ -30,7 +41,24 @@ set [session | global] tidb_replica_read = '<目标值>'; 默认值:leader -该变量用于设置期待的数据读取方式。 +该变量用于设置期待的数据读取方式。从 v8.5.4 开始,该变量仅对只读 SQL 语句生效。 + +在需要通过读取本地副本节省跨区流量的场景下,推荐如下配置: + +- 默认值 `leader` 的性能最好。 +- `closest-adaptive` 在最小性能损失的前提下尽可能节省流量。 +- `closest-replicas` 可以最大程度地节省网络流量。 + +如果当前正在使用其他配置,可参考下表修改为推荐配置: + +| 正在使用配置 | 推荐修改的配置 | +| ------------- | ------------- | +| `follower` | `closest-replicas` | +| `leader-and-follower` | `closest-replicas` | +| `prefer-leader` | `closest-adaptive` | +| `learner` | `closest-replicas` | + +如果希望使用更精确的读副本选择策略,请参考完整的可选配置列表: - 当设置为默认值 `leader` 或者空字符串时,TiDB 会维持原有行为方式,将所有的读取操作都发送给 leader 副本处理。 - 当设置为 `follower` 时,TiDB 会选择 Region 的 follower 副本完成所有的数据读取操作。当 Region 存在 learner 副本时,TiDB 也会考虑从 learner 副本读取数据,此时 follower 副本和 learner 副本具有相同优先级。若当前 Region 无可用的 follower 副本或 learner 副本,TiDB 会从 leader 副本读取数据。 @@ -53,16 +81,42 @@ set [session | global] tidb_replica_read = '<目标值>'; > - 当 `tidb_replica_read` 设置为 `follower` 且无可用 follower 副本及 learner 副本时,TiDB 会报错。 > - 当 `tidb_replica_read` 设置为 `learner` 且无可用 learner 副本时,TiDB 会报错。 +## 基本监控 + +通过观察 [**TiDB** > **KV Request** > **Read Req Traffic** 面板(v8.5.4 新增)](/grafana-tidb-dashboard.md#kv-request),可以帮助判断是否需要使用 Follower Read 以及开启 Follower Read 后查看节省流量的效果。 + ## 实现机制 在 Follower Read 功能出现之前,TiDB 采用 strong leader 策略将所有的读写操作全部提交到 Region 的 leader 节点上完成。虽然 TiKV 能够很均匀地将 Region 分散到多个物理节点上,但是对于每一个 Region 来说,只有 leader 副本能够对外提供服务,另外的 follower 除了时刻同步数据准备着 failover 时投票切换成为 leader 外,没有办法对 TiDB 的请求提供任何帮助。 -为了允许在 TiKV 的 follower 节点进行数据读取,同时又不破坏线性一致性和 Snapshot Isolation 的事务隔离,Region 的 follower 节点需要使用 Raft `ReadIndex` 协议确保当前读请求可以读到当前 leader 上已经 commit 的最新数据。在 TiDB 层面,Follower Read 只需根据负载均衡策略将某个 Region 的读取请求发送到 follower 节点。 +Follower Read 包含一系列将 TiKV 读取负载从 Region 的 leader 副本上 offload 到 follower 副本的负载均衡机制。为了允许在 TiKV 的 follower 节点进行数据读取,同时又不破坏线性一致性和 Snapshot Isolation 的事务隔离,Region 的 follower 节点需要使用 Raft `ReadIndex` 协议确保当前读请求可以读到当前 leader 节点上已经 commit 的最新数据。在 TiDB 层面,Follower Read 只需根据负载均衡策略将某个 Region 的读取请求发送到 follower 节点。 ### Follower 强一致读 -TiKV follower 节点处理读取请求时,首先使用 Raft `ReadIndex` 协议与 Region 当前的 leader 进行一次交互,来获取当前 Raft group 最新的 commit index。本地 apply 到所获取的 leader 最新 commit index 后,便可以开始正常的读取请求处理流程。 +TiKV follower 节点处理读取请求时,首先使用 Raft `ReadIndex` 协议与 Region 当前的 leader 节点进行一次交互,来获取当前 Raft group 最新的 commit index(read index)。本地 apply 到所获取的 leader 节点最新 commit index 后,便可以开始正常的读取请求处理流程。 + +![read-index-flow](/media/follower-read/read-index.png) ### Follower 副本选择策略 -由于 TiKV 的 Follower Read 不会破坏 TiDB 的 Snapshot Isolation 事务隔离级别,因此 TiDB 选择 follower 的策略可以采用 round robin 的方式。目前,对于 Coprocessor 请求,Follower Read 负载均衡策略粒度是连接级别的,对于一个 TiDB 的客户端连接在某个具体的 Region 上会固定使用同一个 follower,只有在选中的 follower 发生故障或者因调度策略发生调整的情况下才会进行切换。而对于非 Coprocessor 请求(点查等),Follower Read 负载均衡策略粒度是事务级别的,对于一个 TiDB 的事务在某个具体的 Region 上会固定使用同一个 follower,同样在 follower 发生故障或者因调度策略发生调整的情况下才会进行切换。如果同一事务内既有点查请求又有 Coprocessor 请求,两种请求都将按照上述调度策略分别进行读取,即使 Coprocessor 和点查出现在同一个 Region 上,TiDB 也会当作独立事件来处理。 +Follower Read 不会破坏 TiDB 的 Snapshot Isolation 事务隔离级别。TiDB 在第一次选取副本时会根据 `tidb_replica_read` 的配置进行选择。从第二次重试开始,TiDB 会优先保证读取成功,因此当选中的 follower 节点出现无法访问的故障或其他错误时,会切换到 leader 提供服务。 + +#### `leader` + +- 选择 leader 副本进行读取,不考虑副本位置。 + +#### `closest-replicas` + +- 当和 TiDB 同一个 AZ 的副本是 leader 节点时,不使用 Follower Read。 +- 当和 TiDB 同一个 AZ 的副本不是 leader 节点时,使用 Follower Read。 + +#### `closest-adaptive` + +- 如果预估的返回结果不够大,使用 `leader` 策略,不进行 Follower Read。 +- 如果预估的返回结果足够大,使用 `closest-replicas` 策略。 + +### Follower Read 的性能开销 + +为了保证数据强一致性, Follower Read 不管读取多少数据,都需要执行一次 `ReadIndex`,这将不可避免的消耗更多的 TiKV CPU 资源。因此,在小查询(如点查)场景下,Follower Read 的性能损耗相对更明显。同时,因为对小查询进行本地读取能节省的流量有限,更推荐在大查询或批量读取场景中使用 Follower Read。 + +当 `tidb_replica_read` 为 `closest-adaptive` 时,TiDB 针对小查询时不会使用 Follower Read,从而在各种工作负载下中相比 `leader` 策略的 TiKV CPU 的额外开销一般在 +10% 之内。 diff --git a/grafana-tidb-dashboard.md b/grafana-tidb-dashboard.md index 18b394b9abac..59c07c6215c7 100644 --- a/grafana-tidb-dashboard.md +++ b/grafana-tidb-dashboard.md @@ -125,6 +125,11 @@ aliases: ['/docs-cn/dev/grafana-tidb-dashboard/','/docs-cn/dev/reference/key-mon - **cross-zone-out**:尝试在远程可用区执行 Stale Read 的请求的响应的传出流量 - **local-in**:尝试在本地可用区执行 Stale Read 的请求的响应的传入流量 - **local-out**:尝试在本地可用区执行 Stale Read 的请求的响应的传出流量 +- Read Req Traffic + - **leader-local**: leader read 在本地读的流量 + - **leader-cross-zone**: leader read 跨 AZ 读的流量 + - **follower-local**: follower read 在本地读的流量 + - **follower-cross-zone**: follower read 跨 AZ 读的流量 ### PD Client diff --git a/media/follower-read/read-index.png b/media/follower-read/read-index.png new file mode 100644 index 000000000000..b20a7047f905 Binary files /dev/null and b/media/follower-read/read-index.png differ diff --git a/system-variables.md b/system-variables.md index 6d4cacbbc0ce..82f2dba7b69e 100644 --- a/system-variables.md +++ b/system-variables.md @@ -3299,7 +3299,7 @@ v5.0 后,用户仍可以单独修改以上系统变量(会有废弃警告) - 该变量用于定义分布式框架任务可使用的 TiDB 节点数上限。默认值为 `-1`,表示启用自动模式。在自动模式下,TiDB 将按照 `min(3, tikv_nodes / 3)` 动态地计算该值,其中 `tikv_nodes` 表示集群中 TiKV 节点的数量。 > **注意:** -> +> > 如果部分 TiDB 节点显式设置了 [`tidb_service_scope`](#tidb_service_scope-从-v740-版本开始引入),则分布式执行框架仅会将任务调度到这些节点中执行。此时,即使 `tidb_max_dist_task_nodes` 设置了更大的值,实际使用的 TiDB 节点数也不会超过显式设置了 `tidb_service_scope` 的 TiDB 节点数。 > > 例如,集群有 10 个 TiDB 节点,其中 4 个节点均设置了 `tidb_service_scope = group1`。此时即使设置 `tidb_max_dist_task_nodes = 5`,实际参与任务执行的节点数仍为 4。 @@ -4811,7 +4811,7 @@ EXPLAIN FORMAT='brief' SELECT COUNT(1) FROM t WHERE a = 1 AND b IS NOT NULL; - 类型:枚举型 - 默认值:`leader` - 可选值:`leader`、`follower`、`leader-and-follower`、`prefer-leader`、`closest-replicas`、`closest-adaptive` 和 `learner`。其中,`learner` 从 v6.6.0 开始引入。 -- 这个变量用于控制 TiDB 的 Follower Read 功能的行为。 +- 这个变量用于控制 TiDB 的 Follower Read 功能的行为。从 v8.5.4 开始,该变量仅对只读 SQL 语句生效。 - 关于使用方式与实现原理,见 [Follower Read](/follower-read.md)。 ### `tidb_request_source_type` 从 v7.4.0 版本开始引入 @@ -5080,7 +5080,7 @@ Query OK, 0 rows affected, 1 warning (0.00 sec) ### `tidb_slow_txn_log_threshold` 从 v7.0.0 版本开始引入 - 作用域:SESSION -- 是否受 Hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value) 控制:否 +- 是否受 Hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value) 控制:否 - 类型:无符号整数型 - 默认值:`0` - 范围:`[0, 9223372036854775807]`