作为一名长期与数据库打交道的 DBA,我在接触 TiDB 分布式数据库的过程中,逐渐积累了一些故障排查的经验和方法论。与传统的单机数据库(如 MySQL、Oracle)不同,TiDB 的分布式架构带来了新的挑战——一个慢查询可能涉及 TiDB Server、PD、TiKV 甚至网络层的多个环节。
本文整理了一套从 监控告警 → 初步定位 → 深入分析 → 根因确认 的故障排查思路,希望对正在学习 TiDB 运维的同学有所帮助。
一、建立排查框架:分层定位法
TiDB 的核心架构分为三层,排查时我习惯按以下顺序逐层排除:
┌─────────────────────────────────────────┐
│ Layer 1: TiDB Server (SQL 层) │
│ → 慢查询、执行计划、连接数、内存 │
├─────────────────────────────────────────┤
│ Layer 2: PD (调度层) │
│ → Region 分布、调度策略、TSO 分配 │
├─────────────────────────────────────────┤
│ Layer 3: TiKV (存储层) │
│ → RocksDB、Raft、Coprocessor、磁盘 IO │
└─────────────────────────────────────────┘
为什么要从上往下查? 因为 80% 的问题最终表现都在 SQL 层(慢查询、报错),但根因可能在下面任意一层。从现象倒推,逐层深入,避免盲目操作。
二、第一层:TiDB Server 快速诊断
2.1 慢查询分析
当收到"数据库慢了"的反馈,第一步永远是查慢查询日志:
sql
复制
-- 查看最近的慢查询(按耗时排序)
SELECT
Time,
Query_time,
DB,
LEFT(Query, 200) AS query_preview,
Digest
FROM information_schema.slow_query
WHERE Time > DATE_SUB(NOW(), INTERVAL 1 HOUR)
ORDER BY Query_time DESC
LIMIT 20;
关键指标:
Query_time> 1s:需要关注Process_timevsWait_time:处理时间大 = SQL 本身复杂;等待时间大 = 资源争抢Cop_processvsCop_wait:Coprocessor 耗时占比,判断瓶颈在 TiDB 还是 TiKV
2.2 查看当前运行的 SQL
sql
复制
-- 正在执行的查询及其状态
SELECT
id,
user,
db,
command,
time AS running_seconds,
state,
LEFT(info, 200) AS current_query
FROM information_schema.processlist
WHERE command != 'Sleep'
ORDER BY time DESC;
state 字段非常有用:
autocommit/fetching rows:正常Sending data:数据量大或网络慢Waiting for ...:等待锁或资源coprocessor:正在 TiKV 侧处理
2.3 执行计划分析
sql
复制
-- 分析慢 SQL 的执行计划
EXPLAIN ANALYZE
SELECT ...
FROM ...
WHERE ...;
重点关注:
cop_task是否过多(说明下推到 TiKV 的任务多)TableFullScan/IndexFullScan:全表扫描,必须加索引HashJoin_*vsIndexJoin_*:大表 Join 用 HashJoin 更高效estRowsvsactRows:估算行数与实际行数差距大,说明统计信息过期
sql
复制
-- 统计信息检查
SHOW STATS_HEALTHY;
-- 低于 80 的表需要重新收集
ANALYZE TABLE table_name;
三、第二层:PD 调度诊断
PD 是整个集群的"大脑"。很多性能问题表面看是 SQL 慢,根因却是 PD 调度异常。
3.1 检查 Region 健康度
bash
复制
# 使用 pd-ctl 工具
pd-ctl -u http://pd-server:2379
# 查看 store 状态
>> store
# 关注:region_count 是否均衡、leader_count 是否倾斜
# 检查 Region 分布
>> region --jq=".regions | group_by(.peers[0].store_id) | ..."
# 查看热点 Region
>> hot read # 读热点
>> hot write # 写热点
3.2 调度状态检查
sql
复制
-- 查看 PD 调度器配置
SHOW CONFIG WHERE type = 'pd' AND name LIKE '%schedule%';
关键配置:
leader-schedule-limit:Leader 调度并发(默认 4)region-schedule-limit:Region 调度并发(默认 2048)hot-region-schedule-limit:热点调度并发(默认 4)
调度的常见问题:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| Region 数量极度不均衡 | 调度被禁用或限制 | 检查 region-schedule-limit |
| Leader 集中在少数 Store | Leader 调度策略异常 | 检查 leader-schedule-limit 和 Store 权重 |
| 热点无法打散 | 热点调度器未启用 | 检查 Split Region 策略 |
| 大量 Region 处于 pending 状态 | PD leader 切换或 Store 异常 | 检查 PD 集群健康状态 |
3.3 TSO 延迟监控
TSO 是 TiDB 分布式事务的时间戳服务,TSO 慢会导致全局变慢:
sql
复制
-- 查看 TiDB 侧的 TSO 等待时间
-- 在 Grafana 监控中查看:TiDB → PD Client → PD TSO RPC Duration
-- P99 > 100ms 需要关注
bash
复制
# pd-ctl 查看 TSO 分配情况
>> tso
四、第三层:TiKV 深度排查
TiKV 是数据的最终存储层。到这层排查时,通常已经定位到具体 Region 或 Store 有问题。
4.1 RocksDB 相关
RocksDB 的 write stall 是 TiKV 最常见的性能杀手:
bash
复制
# 查看 Store 详细信息
tikv-ctl --host tikv-server:20160 raft-store --dump
# 检查 RocksDB 指标(Grafana)
# TiKV-Details → RocksDB-kv → Write Stall Duration Max
# 如果经常 > 0,说明写入压力大或 Compaction 跟不上
write stall 的常见原因和解决方案:
- memtable 满了
- 现象:写入突然变慢,Grafana 显示 Write Stall
- 解决:增大
write-buffer-size或提高max-write-buffer-number
- Level 0 文件数过多
- 现象:Compaction 跟不上写入速度
- 解决:调整
level0-slowdown-writes-trigger和level0-stop-writes-trigger
- Pending Compaction Bytes 过大
- 现象:磁盘 IO 打满
- 解决:检查磁盘性能,考虑扩容或使用性能更好的磁盘
4.2 Raft 相关
bash
复制
# 查看 Region 的 Raft 状态
pd-ctl -u http://pd-server:2379 region <region-id>
# 查看 peer 状态
pd-ctl -u http://pd-server:2379 region sibling <region-id>
Raft 常见问题:
- Leader 频繁切换:检查网络延迟、磁盘 IO
- Raft Log 堆积:Follower 落后太多,可能需要快照同步
- Region 无法选出 Leader:多数副本异常,需要紧急处理
4.3 Coprocessor 执行慢
Coprocessor 是 TiKV 侧的计算引擎。当 SQL 的 cop 任务耗时长:
sql
复制
-- 查看 Coprocessor 慢请求(需开启慢日志)
-- 关注 TiDB 日志中的 cop_backoff 信息
-- 常见 backoff 类型:
-- txnLock:事务锁冲突
-- regionMiss:Region 分裂/合并期间
-- tikvRPC:TiKV 响应慢
-- pdRPC:PD 响应慢
五、实战案例:一次"数据库突然变慢"的完整排查
5.1 现象
用户反馈:下午 3 点左右,业务写入突然变慢,P99 从 50ms 飙升到 5s。
5.2 排查过程
Step 1:检查慢查询
sql
复制
SELECT Time, Query_time, LEFT(Query, 200)
FROM information_schema.slow_query
WHERE Time BETWEEN '2024-06-01 14:50:00' AND '2024-06-01 15:10:00'
ORDER BY Query_time DESC LIMIT 10;
发现 80% 的慢查询都是简单的 INSERT 语句,但 Cop_wait 很高。
Step 2:检查存储层
进入 Grafana,定位到对应 TiKV 节点:
RocksDB Write Stall Duration持续 > 0Pending Compaction Bytes高达 200GB+
Step 3:确认根因
原来是一小时前有一个离线数据导入任务,短时间内写入了大量数据,导致 Compaction 积压。
5.3 解决措施
- 短期:暂停导入任务,让 Compaction 自然消化积压数据
- 中期:调整 RocksDB 参数,增加 Compaction 线程
- 长期:大表导入采用分批策略,避免对在线业务造成影响
六、排查工具速查表
| 工具 | 用途 | 常用命令 |
|---|---|---|
| pd-ctl | PD 集群管理 | store, region, hot, config show |
| tikv-ctl | TiKV 节点调试 | raft-store --dump, size, compact |
| tidb-ctl | TiDB 管理 | schema, region |
| Grafana | 监控大盘 | TiDB / PD / TiKV-Details |
| 慢查询日志 | SQL 分析 | information_schema.slow_query |
| TiDB Dashboard | 可视化诊断 | SQL 分析、流量可视化、日志搜索 |
写在最后
分布式数据库的运维本质上考验的是 分层排查能力 和 对系统架构的理解深度。TiDB 的模块化设计让排查有了清晰的路径,但真正决定效率的,还是排查者是否建立了正确的排查框架。
以下是个人总结的排查心法:
- 现象驱动,不要猜测 — 先看监控和日志,不要凭经验盲改
- 逐层排查,不要跳层 — 80% 的问题不需要动到 TiKV
- 改之前先备份配置 — 用
SHOW CONFIG或者 pd-ctl 导出当前配置 - 一次只改一个变量 — 参数调优切忌多变量同时调整
- 保持学习 — TiDB 社区(AskTUG)和官方文档是最好的学习资源
本文为个人学习与实践总结,欢迎在评论区交流讨论。如果你正在准备 TiDB 认证或者日常运维中遇到问题,也欢迎一起探讨!
作者注:本文参考了 TiDB 官方文档、AskTUG 社区讨论以及 305-TiDB 故障排除课程大纲。如有不足之处,恳请指正。