【 TiDB 使用环境】生产环境
【 TiDB 版本】v7.5 v8.5
【复现路径】tidb配置了max_execution_time=2s, 执行一个耗时长的scan 或 coprocessor语句
【遇到的问题:问题现象及影响】tidb配置了max_execution_time=2s,超时断链后,TIKV任务还在跑,因为TIKV侧deadline任务超时时间是60s。疑问: 能否配置tikv_client_read_timeout = 3s来缩短TIKV侧的deadline,加快Tikv的任务出清?
【资源配置】
【附件:截图/日志/监控】
这个参数的定义,貌似不是这么理解的,
你的描述是 Client → TiDB → Tikv,然后 client 和 tidb 的 connect 已经关闭,如果 task close 理论上 tidb → Tikv 所有的 process 都需要停止并回收掉才对的。
可以看下原文:
在通常情况下,TiKV 处理请求非常快,只需几毫秒。但是,当某个 TiKV 节点遇到磁盘 I/O 抖动或网络延迟时,请求处理时间可能会大幅增加。在 v7.4.0 以前的版本中,TiKV 请求的超时限制是固定的,不能调整。因此,当 TiKV 节点出现问题时,TiDB 必须等待固定时长的超时响应,这导致了抖动期间应用程序的查询性能受到明显影响。
TiDB 在 v7.4.0 中引入了一个新系统变量 tikv_client_read_timeout,你可以自定义查询语句中 TiDB 发送给 TiKV 的 RPC 读请求的超时时间。这意味着,当某个 TiKV 节点因磁盘或网络问题导致请求延迟时,TiDB 可以更快地超时并将请求重新发送给其他 TiKV 节点,从而降低查询延迟。如果所有 TiKV 节点的请求都超时,TiDB 将使用默认的超时时间进行重试。此外,你也可以在查询语句中使用 Optimizer Hint /*+ SET_VAR(TIKV_CLIENT_READ_TIMEOUT=N) */ 来设置 TiDB 发送 TiKV RPC 读请求的超时时间。这一改进将使 TiDB 在面对不稳定的网络或存储环境时,更灵活地适应各种情况,提高查询性能,提升用户体验。
不建议直接改 tikv_client_read_timeout 来解决这个问题。这个参数主要影响TiDB和TiKV之间的网络读超时,强行调小可能导致正常请求误判超时,引发更多问题。
针对你的场景,更稳妥的做法是:
- 在TiDB侧设置
tikv_client_read_timeout = "3s"后,同时观察监控中tikv_cop_requests和deadline相关指标,确认是否真的能加速出清,但生产环境建议先在测试环境验证。
1、v7.5.0 之前:没有copr‑req‑timeout配置,TiDB 无法下发 deadline 给 TiKV;只能靠 tikv 内置固定 60s 硬超时,没有办法从 tidb 侧缩短 tikv 任务时长。只能业务层、索引、SQL 优化。 2、v7.5 ~ v8.5:支持 copr‑req‑timeout 参数,可以下发 deadline 给 TiKV,是解决你这个场景的正规方案GitHub 3、即使配置了copr‑req‑timeout,max_execution_time依然优先控制 TiDB 上层 SQL 超时;两个值建议配套。
不建议用tikv_client_read_timeout处理这个场景,该参数只是 TiDB 等待 TiKV 返回包的网络 IO 超时,并不会下发取消指令,TiKV 上的 cop 任务依旧会继续执行。
有可以复现的SQL用例吗
不会取消 TiKV 上已经在跑的 cop task,两者管的是不同层级的超时,机制不一样。
强行调小可能导致正常请求误判超时,引发更多问题 -----能给一个例子吗?
1. 现状与机制分析
- 带 Deadline 机制:根据 8.5 源码,设置
tikv_client_read_timeout = 3s后,该超时时间会作为deadline透传给 TiKV,定义为 TiKV 侧的最大允许执行时间。任务进入 Unified Read Pool 后,会在特定检查点判断是否已达deadline,若达到则立即主动终止执行。 - 无 Deadline 机制(协作式退出):若未透传
deadline,Read Pool 中的任务采用协作式(Cooperative)退出机制:- 未入队:可直接取消。
- 已入队 / 正在执行:无法被抢占式中断。任务会继续执行,直至到达下一次“结果写回检查点”;当尝试向客户端写回数据并捕获到网络异常时,才会感知到连接断开并退出。
2. 实际痛点场景(Cop Task 无法中断)
在某些 Coprocessor 耗时较长的场景下,若 TiDB 侧先达到超时(例如超过 2s)并主动关闭连接,Context 取消会触发 TiDB 向 TiKV 发送 stream reset 报文。但由于上述机制限制:
- Executing 状态的 Task 无法及时感知连接断开,必须一路执行完大部分逻辑直到“数据写回”阶段;
- 这导致已无意义的 Read Pool 任务持续消耗 CPU 和 I/O 资源,无法真正被及时取消。
3. 优化思路与担忧
- 解决思路:虽然
tikv_client_read_timeout的初衷是控制 TiDB 侧的读取超时,但通过将deadline下发给 TiKV,使其能够主动根据时间检查终止超时 Task,正好可以补齐目前 Read Pool 缺乏“执行中取消/超时中断”的短板。 - 主要担忧:引入该配置后,除了能够主动超时中断长 Task 外,是否存在其他潜在副作用(例如高并发下短查询被误杀、大查询的重试放大、或者对事务/全局锁等其他阶段逻辑的意外影响)?
不要怀疑这个机制,我现在是担心这样设置会不会带来额外的副作用,如果有,具体是什么。 国内AI搜索的答案,不对着代码的回答,请走开,纯浪费眼力。
tikv_client_read_timeout这个参数控制的是 TiDB 发往 TiKV 的单次 RPC 读请求超时时间,主要用于 TiKV 出现网络抖动或 I/O 延迟时,让请求尽快超时,并尝试切换到其他 Region Peer。并不控制 TiKV Coprocessor 任务的执行超时时间。
如果把这个参数设置得过小,执行大范围 Scan 时,即使 TiKV 端任务本身运行正常,也可能因为单次 RPC 耗时超过 3 秒而频繁触发超时和重试,反而增加 TiDB 和 TiKV 的额外压力。
TIKV侧deadline任务超时时间是60s,应该是 tikv-client.copr-req-timeout 这个参数,从 7.5 版本开始默认值就是 60 秒,好像哪里看到过不建议修改。
另外max_execution_time 控制的是 SQL 层面的执行时间。TiDB 侧 SQL 超时后,下游已经提交到 TiKV 的 Coprocessor 任务,退出过程不一定能够完全同步,也不一定会立即结束。
有道理, tikv_client_read_timeout 控制的是 TiDB 发往 TiKV 的 RPC 读请求超时时间,主要是用来处理 TiKV I/O 抖动或者网络延迟的,超时后 TiDB 可能会换其他 Region Peer 重试,并不是用来控制 TiKV 上已经下发的 Coprocessor 任务多久退出
可以。max_execution_time 只在 TiDB 侧掐断 SQL,TiKV coprocessor 默认仍可能跑到约 60s 的 deadline。把 tikv_client_read_timeout 调到比语句超时略大(例如 3s)能更快取消对 TiKV 的 RPC。不要设得过小,以免正常慢查询被误杀;改完用一条会超时的 scan 看 TiKV CPU 是否尽快回落。
tikv-go-client里面的代码,tikv rpc timeout是会进行重试, 但是业务和TIDB之间的连接已经超时被killed, 重试前会进行检查killed标识。 也就是说,max_execution_time=2s,tikv_client_read_timeout = 3s,tikv rpc超时错误根本不会进行重试。
问题归纳
社区 topic/1059924:v7.5/v8.5 配 max_execution_time=2s 超时断链后,TiKV 侧 cop 任务仍在跑(TiKV deadline 默认 60s)。用户问:能否用 tikv_client_read_timeout=3s 缩短 TiKV 侧 deadline、加快任务出清?
结论(三 agent 一致)
① 机制上「能缩短 deadline」,但「不能加快出清已 running 的任务」
- deadline 真透传:TiDB
coprocessor.go:1197-1199算 timeout(tikv_client_read_timeout>0时覆盖默认)→ client-goclient.go:632context.WithTimeout设 gRPC deadline → TiKV 端在 yield 检查点强制返回(tracker.rs:449+endpoint.rs:858,TICKET-3796 日志铁证)。 - 但 TiKV 无 running-task 取消机制:design doc 官方口径 “once the read task is spawned to the read pool it could not be canceled anymore”,只能在 scan batch/chunk/region 边界提前返回,掐不断已出队的 executor。
② 「断链后 TiKV 仍跑 ~60s」是符合预期的默认行为,不是 bug
max_execution_time与 cop 请求 deadline 完全解耦:它不写进 timeout 计算(timeout 只由CoprReqTimeout默认 60s 与tikv_client_read_timeout决定),kill 走Next()检查的Killed标志,不 cancel 在途 gRPC。印证 TICKET-4385 金句「TiKV 要做完这些操作才能停止」。
③ 用户担心的两个副作用全部命中(不建议 global 设 3s)
tikv_client_read_timeout是全局读路径参数,语义是「超时→换副本重试」,不是「清理残留」。- 设 3s 若低于集群 cop 请求 P99 → 逐副本超时 → 重试放大 → 极端整体报
1105 Coprocessor task terminated...(TICKET-3796 实测:500ms 时 QPS 1010→55;10ms 直接整体失败)。
版本可用性(源码确认)
tikv_client_read_timeout(原名tidb_kv_read_timeout):v7.4.0 引入,v7.5/v8.5 均可用;session+global+hint;单位 ms;默认 0(=不覆盖,走 CoprReqTimeout 60s)。tikv-client.copr-req-timeout:v7.4.0 引入,默认 60s,v7.5/v8.5 均可用。两者设的是同一个 gRPC deadline,前者(sysvar)按请求覆盖后者(config 默认值)。
建议口径
- 不推荐 global 设 3s;先定位慢查询根因(慢 SQL / 大 scan / 副本异常)。
- 若一定要压 TiKV deadline:红线 = 不低于正常期 kv request duration P99,且用单查询 hint
/*+ SET_VAR(tikv_client_read_timeout=N) */,勿 global。
对客答复草稿(可直接回社区)
能缩短 deadline,但不能「加快出清」已跑起来的任务,且 3s 副作用大,不建议 global 设。分三层:
① deadline 确实会被缩短——TiDB 发 cop 前算 timeout(pkg/store/copr/coprocessor.go:1197-1199):timeout := CoprReqTimeout(默认60s); if tikvClientReadTimeout>0 { timeout = tikvClientReadTimeout }。tikv_client_read_timeout(单位 ms,v7.4 引入,原名 tidb_kv_read_timeout)>0 时会覆盖默认 60s,client-go client.go:632 用 context.WithTimeout 把它设成 gRPC deadline 传给 TiKV,TiKV 在检查点强制返回(tracker.rs:449/endpoint.rs:858 报 Coprocessor task terminated due to exceeding the deadline)。所以「把 TiKV 生命周期从 60s 压到 3s」单看机制成立。
② 但它掐不断 running 任务:TiKV 对已进 read pool 的任务无取消机制(design doc 2023-06-30-configurable-kv-timeout.md 原话 “once the read task is spawned to the read pool it could not be canceled anymore”),只在 batch/chunk/region 边界提前返回。所以「断链后仍跑」根因不是 deadline 太长,而是 TiKV 本就无法抢占式中断出队 executor。
③ 3s 危险:tikv_client_read_timeout 是全局读路径参数,语义是「超时→换副本重试」而非「清理残留」。设 3s 若低于集群 cop 请求 P99,会逐副本超时→重试放大,极端整体报 1105(实测:设 500ms 时 QPS 1010→55,设 10ms 直接整体失败)。
建议:先定位为什么慢(慢 SQL / 大 scan / 副本异常);若确要压 TiKV deadline,红线不低于正常期 kv request duration P99,且用单查询 hint 而非 global。
以上是我这边 Loop 跑的,根据内部 KB 、源码分析和工单经验给的结论,看下吧。
- 当前版本:
max_execution_time超时之后,缺少机制去主动 Cancel 已经下发的 cop 任务。TiDB 断连接,TiKV 侧只能等到coprocessor‑timeout到期才清理任务。 - 方案 1(治本):SQL 层面优化,给慢 scan 语句加索引,避免大量全表扫描 cop 任务,优先推荐。
- 方案 2(配置兜底):调小
[tikv-client].coprocessor-timeout,例如 10‑20s,全局缩短 TiKV cop 最大生命周期;评估业务能否接受,避免正常查询被误伤。 - 方案 3:应用层做超时控制,业务侧不要把超大 scan 丢给数据库;
军,如果业务端有低效SQL高并发无法限流,业务允许临时屏蔽这条SQL,在V6.5版本下有个方案是对这条SQL做个 /+ MAX_EXECUTION_TIME(10) / 的sql binding来作为DB测的限流手段,是不是在V8版本里可以改为 /+ MAX_EXECUTION_TIME(10) SET_VAR(TIKV_CLIENT_READ_TIMEOUT=10)/ 更彻底?