写点什么

将业务从 mysql 迁移至 TIDB,有哪些需要注意的?

  • 2022-11-18
    北京
  • 本文字数:3347 字

    阅读完需:约 11 分钟

原文来源:https://tidb.net/blog/ff305fb6

背景

双十一刚过,至此,两个月前我们从 mysql 迁移到 TIDB 的一套业务算是正式成功了。


集团有一套业务库,对接淘宝流量,据说每年双十一的时候流量过大会导致各种问题,苦不堪言。经过内部评估,我们决定将这套系统从 mysql 迁移到更适合大数据量的 TIDB 上。


文章主要是分享一些从 mysql 迁移到 tidb 遇到的问题,以及如何解决。

一、误设置过长 GC

由于这套系统之前是跑在 mysql 上,所以初期数据库的一些工作,是由 mysql 的 dba 和我们 tidb 团队一起工作,某一天我们突然发现集群的 druation 突然上升,并且是在没有更多请求的情况下,延迟上升了。后面经过我们排查发现是 mysql 的 dba 为了在数据库中保存最近 7 天的数据,并且实现误操作闪回,将tidb_gc_life_time 这个参数由 1h 改成了 7d, 从而导致 tikv 中历史版本过多,导致每次磁盘读取会扫描过多的无用数据,导致的整体变慢。

为什么里在 mysql 里面可以设置保留更多的历史数据,tidb 不行?

基于 mysqlDBA 的操作,我思考了一下为什么他直接就将 gc 保留的时间设置长了,研究发现 mysql 的闪回是通过本地保存 binlog 日志实现的,且 mysql 中事务的一致性读是通过 undo log 实现的,所以这里并不会显著的影响正常数据的查询。


而在 tidb 中的闪回和一致性读是直接依赖本地保留的历史版本数据,直接保存各个版本数据实现 mvcc, 再通过 gc 定期清除历史版本数据。


mysql 在进行 mvcc 控制的时候,读取历史的版本,依赖的是:事务开始时间戳、当前的数据、undo log 日志链。在事务中中在读取历史版本数据时,会先找到最新的数据,依靠每行数据自带的回滚指针,去 undo log 中找到事务开始时间戳前最近的一个版本,按时间有序的链表查找历史数据。



而在 tidb 中,所有的 dml 操作都转化为在磁盘中进行追加一行新的数据,最新的数据和历史版本的数据都保留在了一起,在读取数据时,会先将附近版本的数据全部读取,再根据所需版本进行过滤,这样当保留了过多版本的历史数据时,每次读取都会读取很多无用的数据,造成性能开销



tidb 中历史版本过多相关问题,及排查方案

在这篇文章中,就讲到了历史版本过多的一些排查方式,比较全面


一次 TiDB GC 阻塞引发的性能问题分析 - hey-hoho 的专栏 - https://tidb.net/blog/9d17543d?shareId=a9db6401


文章中比较直观的描述了历史版本数据过多时,对于 sql 执行直接的影响:


二、SQL 调优方式对比和 SQL 调优

sql 作为和数据库交互的标准语言,sql 调优是 dba 以及数据库使用者绕不开的东西。


这一小结讲一下相比于 mysql 的 sql 调优方式,在 tidb 中的不同之处,以及讲下将业务从 mysql 迁移到 tidb 后,sql 方面需要做的一些工作。

日常 sql 调优分析对比

在 mysql 数据库的日常调优中,免不了的有类似需求:


#查询频率show global status like 'com*'#查看慢查询日志cat slow_query.log#查看sql耗时以及到底耗费在哪里show profile for query query_id#查看sql执行计划,分析效率explain query
复制代码


而在 tidb 中,集群自带的监控 dashboard 可以满足所有上述需求,并且还拥有统计功能、top 功能、多种条件过滤功能,帮助分析异常以及 sql 调优,非常方便。


mysql 迁移到 tidb 后可能会遇到的一些 sql 调优的工作

在 mysql 迁移至 tidb 后,有一部分原来执行没有性能问题的 sql, 在 tidb 中出现了性能问题,主要有如下:


  • 偶发性的复杂 sql 的连接算子不合理


这类 sql 主要表现为比较复杂的 sql, 且 sql 中的表连接是隐式连接时出现几率大


解决方案:绑定执行计划,此方案对应用代码没有侵入性,且方便快捷,参考:执行计划管理 (SPM) | PingCAP Docs


  • sql 执行逻辑不佳


通常指的是在部分复杂 sql 中,在不影响 sql 最终结果的前提下,先过滤计算某一部分结果作为临时表,会使整个 sql 的效率提高,在部分场景中 mysql 优化器能够自动优化处理,tidb 的执行计划不太合理


解决方案:这种通常只有改写 sql, 在 sql 中去显示的制作临时表


  • 部分小 bug


这种问题通常指某些 sql 导致的异常行为,多在后续版本中被修复了。


例如某些场景下 index hash join 算子会存在一些问题,通过 hint 其他算子可绕过


解决方案:在 github 搜索相关 issue 或者 pr, 或者社区提问

热点问题

相比于单机的 mysql 数据库,分布式 tidb 优势的一点就是可以利用分布式集群多机器的能力来突破单机的 io 瓶颈,但是在某些时候,由于数据分布不合理,或者是业务专一的访问某一小部分的数据,这种时候可能会导致分布式集群中单机的瓶颈成为整个集群的瓶颈,这就是热点问题。

热点的排查与解决

通常我们排查热点最常见的方法就是 dashboard 中的热力图来确认排查热点,越亮的区域,表示流量越高



但是有时候我们很难去确认哪些流量才是真的达到了某一单机器的瓶颈,我这里提供一个方法


1、查询都热点,得到region_id和都流量数值(在一般系统中,70%以上的请求为读请求)SELECT DISTINCT region_id ,read_bytes FROM INFORMATION_SCHEMA.tikv_region_status WHERE ORDER BY READ_BYTES DESC
2、尝试去切分热点regiontiup ctl:v5.3.2 pd -u http://10.0.*.*:2379 operator add split-region $id --policy=scan
3、若观察到切分该region后duration有比较明显的下降,则说明该流量比较容易达到机器瓶颈(当然一台机器肯定不止只有一个region被访问,所以这里其实是一个观察性质的经验,不是具体某一个数值)
复制代码


结合确定的流量瓶颈,我写了个简单的脚本挂在 crontab, 每隔 20 分钟执行一次,效果不错


#!/bin/bash
#打印当前时间echo "############################################">>/home/tidb/log/split-hot-region.logdate>>/home/tidb/log/split-hot-region.log
#查找读流量大于5G的regionhot_id=`mysql -h10.0.6.61 -P4000 -uroot -pCnwRwdF%ftm -e"SELECT DISTINCT region_id FROM INFORMATION_SCHEMA.tikv_region_status WHERE READ_BYTES >5368709120 ORDER BY READ_BYTES DESC"`
#打印热点region_id和读流量到日志echo "当前读热点为:">>/home/tidb/log/split-hot-region.logmysql -h10.0.*.* -P4000 -uroot -p**** -e"SELECT DISTINCT region_id ,read_bytes FROM INFORMATION_SCHEMA.tikv_region_status WHERE READ_BYTES >5368709120 ORDER BY READ_BYTES DESC">>/home/tidb/log/split-hot-region.log
source /home/tidb/.bash_profilefor id in $hot_iddoif [ $id != 'region_id' ];thentiup ctl:v5.3.2 pd -u http://10.0.*.*:2379 operator add split-region $id --policy=scansleep 1stiup ctl:v5.3.2 pd -u http://10.0.*.*:2379 operator add split-region $id --policy=scansleep 1stiup ctl:v5.3.2 pd -u http://10.0.*.*:2379 operator add split-region $id --policy=scansleep 1stiup ctl:v5.3.2 pd -u http://10.0.*.*:2379 operator add split-region $id --policy=scansleep 1stiup ctl:v5.3.2 pd -u http://10.0.*.*:2379 operator add split-region $id --policy=scan if [ $? -eq 0 ]; then echo "已成功切分region "$id>>/home/tidb/log/split-hot-region.log else echo "切分region"$id"失败">>/home/tidb/log/split-hot-region.log fifidone

复制代码


当然也可以通过调整系统参数实现,Load Base Split | PingCAP Docs


(某次设置这两个参数不小心搞错,碰到一些问题,有阴影了,现在不想用)


大范围热点处理

有些时候,热点可能是由于 sql 不合理所导致的,例如对某张表的查询没有建立索引,导致每次都是全表扫之后再过滤,导致的大块热点。(如果有索引,每次定向读取少量数据,就不会有热点)


排查与解决方案:


这种通常的碰到之后,根据热力图中的表名去查询相关的 sql,去验证执行计划中是否走了索引,后续添加索引。


也有一部分为 sql 写的不合理,每次请求大量的数据,到应用服务器之后再进行过滤,这种就需要与开发进行讨论添加过滤条件。

其他问题处理

一个比较久远的帖子,写的内容比较全面和基础,可以参考一下


专栏 - 迁移 MySQL 集群到 TiDB 相关问题整理 | TiDB 社区

作者看法

tidb 作为兼容 mysql 的分布式数据库,未来必然会有越来越多的业务从 mysql 上面迁移到 tidb, 我希望有越来越多的案例和经验可以被分享出来,作为参考。


发布于: 刚刚阅读数: 3
用户头像

TiDB 社区官网:https://tidb.net/ 2021-12-15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
将业务从mysql迁移至TIDB,有哪些需要注意的?_管理与运维_TiDB 社区干货传送门_InfoQ写作社区