作者:李文杰 数据架构师,TUG 广州地区流动组织者
在日常业务应用或运维治理 TiDB 的过程中,每个开发人员或数据库管理员都或多或少遇到过 SQL 变慢的问题。这类问题大部分状况下都具备肯定的法则可循,通过教训的积攒能够疾速的定位和优化。然而有些状况下不肯定很好排查,尤其波及到内核调优等方向时,如果当时没有对各个组件的互访关系、引擎存储原理等有肯定的理解,往往难以下手。
本文针对写 TiDB 集群的场景,总结业务 SQL 在写忽然变慢时的剖析和排查思路,旨在积淀教训、共享与社区。
写入原理
业务对集群的数据写入流程会被 TiDB Server 封装为一个个的写事务,写事务的实现次要波及的组件是 TiDB Server 和 TiKV Server。如下所示,是 TiDB 集群写入流程的架构简图:
事务在写入的过程,别离会与 TiDB Server、PD 和 TiKV Server 进行交互:
TiDB Server
用户提交的业务 SQL 通过 Protocol Layer 进行 SQL 协定转换后,外部 PD Client 向 PD Server 申请到一个 TSO,此 TSO 即为事务的开始工夫 txn_start_tso,同时也是事务在全局的惟一 ID
接着 TiDB Server 对 SQL 文本进行解析解决,转为形象语法树 AST 传给下一个解决模块
TiDB Server 对 AST 进行编译、SQL 等价改写等逻辑优化、参考零碎统计信息进行物理优化后,会生成真正能够执行的打算
可执行的打算通过分析判断,点查问操作转到 KV 模块、简单查问转到 DistSQL 模块(持续转为对单个表拜访的多个申请),再通过 TiKV Client 模块与 TiKV 进行交互,在 TiDB Server 这一侧实现对数据的拜访
TiKV Server
TiKV 的 Scheduler Worker Pool 模块负责接管通过 gRPC 传过来的写申请数据,在这里它能实现写入流量的管制、锁抵触查看与获取(latch)、快照(snapshot)版本比照的性能
后面的校验通过后,写入的数据会进入到 Raftstore Pool 模块,它会将写入数据的申请封装为 raft log(Propose),在本地长久化(append)的同时并发散发到 follower 节点,接着实现 raft log 的 commit 操作,最初将 raft log 日志数据写入到 rocksdb raft
Apply Pool 模块充当消费者的的角色,会生产 rocksdb raft 外面的日志数据,转为真正的 KV 数据存储到 rocksdb KV,至此实现了一次写入数据的流程
- rocksdb 外面的数据写入包含了 LSM Tree 的写入过程,次要方面有 WAL、MemTable、Immutable Table、L0~L6 层的内存或磁盘 IO 操作,这里并没有具体论述,有趣味的能够返回官网查阅。
图中 Raftstore Pool 和 Apply Pool 这两步通常统称为 Async Write 操作,这个是 TiKV 写入数据的要害流程,也是数据写入剖析的重点环节所在。
- Raftstore Pool 和 Apply Pool 解决数据的过程波及到线程池的调度和解决等,次要耗费 CPU 资源
- rocksdb raft 和 rocksdb kv 因为波及到数据落盘,次要耗费磁盘 IO 资源
- 数据在不同 TiKV 节点之间进行复制、同步等,次要耗费网络带宽 IO 资源
写变慢排查思路
惯例排查
通常业务的 SQL 变慢后,咱们在 TiDB Server 的 Grafana 面板能够看到整体的或者某一百分位的申请提早会升高, 咱们能够顺次排查物理硬件环境、是否有业务变更操作、数据库运行的状况 等,定位到问题后再针对性解决。
如上图是一个写入慢的惯例排查思路,在理论工作中对于各项内容的排查能够同时进行,穿插剖析,互相配合定位问题所在。
遇到问题,先到 Dashboard 看看,对整个集群运行状况有个整体的把握
- 查看集群热力求,关注集群高亮的区域,剖析是否有写热点呈现,如果有则确认对应的库表、Region 等信息
- 排查慢 SQL 状况,查看集群慢查问后果,剖析 SQL 慢查问起因
- 查看 TOP SQL 面板,剖析集群的 CPU 耗费与 SQL 关联的状况
物理硬件排查
- 排查客户端与集群之间、集群外部 TiDB、PD、TiKV 各组件之间的网络问题
- 排查集群的内存、CPU、磁盘 IO 等状况,尤其是混合部署的集群,确认是否存在资源相互竞争、挤兑的场景呈现
- 排查操作系统的内核操作是否与官网倡议的最佳实际值是否统一,确认 TiDB 集群运行在最优的零碎环境内
业务变更
- 确认是否是新上线业务
- 查看集群的 DDL Jobs,确认是否因为在线 DDL 导致的问题,特地是大表加索引的场景,会耗费集群较多的资源,从而烦扰集群失常的拜访申请
全链路排查
对于惯例剖析无奈确认的或者简单业务的问题,通常排查起来比拟辣手,这时候能够 剖析数据从写入 TiDB Server 到 TiKV Server、再落盘至 RocksDB 的整个过程 ,对全副写入链路逐个进行排查,从而确认写入慢所在的节点,定位到起因后再进行优化即可,这一过程大抵如下图所示。
毫无疑问,这个是一个兜底的排查思路,适用范围较广,通用性较强,然而排查起来要花费更多的工夫和精力,也要求管理员对数据库自身的运行原理有肯定的把握。
对于写入慢的全链路剖析,咱们首先在问题时段从整体上把握提早状况,再剖析 TiDB Server 和 TiKV Server 在对应时段的提早,确认问题处于计算层还是存储层,接着再深入分析
- 对于 TiDB Server 层,次要察看 SQL 的解析优化过程耗时,以及和 PD 进行交互过程的提早状况
- 对于 TiKV Server 层,重点关注 Scheduler Worker Pool、Raft log 同步复制与写入、Apply 这几个过程
下面的写入过程的提早状况,能够从集群的 Grafana 监控面板察看失去, 其中 TiKV 是重点所在 ,其每个阶段写入的流程以及对应在 Grafana 上的提早监控面板如下。
gRPC duration 或 Scheduler command duration 示意整个写入过程在 TiKV 侧的耗时状况
- gRPC duration 是申请在 TiKV 端的总耗时。通过比照 TiKV 的 gRPC duration 以及 TiDB 中的 KV duration 能够发现潜在的网络问题。比方 gRPC duration 很短然而 TiDB 的 KV duration 显示很长,阐明 TiDB 和 TiKV 之间网络提早可能很高,或者 TiDB 和 TiKV 之间的网卡带宽被占满
- TiKV Details 下 Scheduler – commit 的 Scheduler command duration 示意执行 commit 命令所需破费的工夫,失常状况下,应该小于 1s
TiKV Details 下 Scheduler – commit 的 Scheduler latch wait duration 示意因为等到锁 latch wait 造成的工夫开销,失常状况下应该小于 1s
TiKV Details 下 Storage 的 Storage async snapshot duration 示意异步解决 snapshot 所破费的工夫,99% 的状况下应该小于 1s
TiKV Details 下 Storage 的 Storage async write duration 示意异步写所破费的工夫,99% 的状况下应该小于 1s
TiKV Details 下 Raft propose 的 Propose wait duration 示意将写入数据申请转为 raft log 的等待时间
TiKV Details 下 Raft IO 的 Append log duration 示意 Raft append 日志所破费的工夫
TiKV Details 下 Raft IO 的 Commit log duration 示意 Raft commit 日志所破费的工夫
TiKV Details 下 Raft propose 的 Apply wait duration 示意 apply 的等待时间
TiKV Details 下 Raft IO 的 Apply log duration 示意 Raft apply 日志所破费的工夫
通过比照剖析不同阶段的提早在整体中的占比,通常能够定位到比较慢的环节,而后再针对性优化即可。
官网的 Dashboard 曾经帮咱们把各个环节汇总了起来,定位到具体的慢写入 SQL 后,能够查看其执行工夫,上面是一个例子,外面每个环节的耗时和解释都写得十分分明,大大降低了问题排查的难度和工夫,十分好用:
总结
- 惯例写入慢的问题,咱们能够顺次排查物理硬件环境、是否有业务新上线,是否有 DDL 变更操作、执行打算不准、热点问题等状况,通常能够定位到问题,再针对性解决。
- 对于简单问题则须要对写入过程逐个剖析和比照,通常须要重复察看、比照、验证能力找到基本的起因。
对于开发人员或 DBA,会解决具体的问题是一项很重要的能力,但定位问题根因所在的能力更难能可贵!
这里想表白的意思,和大家耳熟能详的故事殊途同归:
“老师傅,故障已排除,但就凭这一条线也要 10000$?!”
“画这条线要 1$,但晓得在哪里画要 9999$!”