扫码阅读
手机扫码阅读

TiDB丨 从MySQL迁移至TiDB的常见问题及解决方案

319 2023-09-21



TiDB

神州数码云基地

在 TiDB 上的尝试、调研与分享



本期内容

数据库迁移问题及解法


集团有一套业务库,对接淘宝流量。据说每年双11的时候,流量过大都会导致各种问题,苦不堪言。


经过内部评估,我们决定将这套系统从MySQL迁移到更适合大数据量的TIDB上。


经过团队的共同努力,我们完成了迁移,并在2022年“双11”期间经受住了考验,所以本期就跟大家分享一些从MySQL迁移到TIDB,我们遇到的问题,以及最后是如何解决

GC设置过长的问题

由于这套系统之前是跑在MySQL上,所以初期数据库的一些工作,是由MySQL的DBA和我们TiDB团队一起协作完成的。

某一天我们突然发现,集群的druation突然上升,并且是在没有更多请求的情况下,延迟上升了

经排查发现,是MySQL的dba为了在数据库中保存最近7天的数据,并且实现误操作闪回,将 tidb_gc_life_time 这个参数由1h改成了7d,从而导致tikv中历史版本过多,导致每次磁盘读取会扫描过多的无用数据,导致的整体变慢。

为什么在MySQL里可设置

保留更多的历史数据,而TiDB不行?

基于 MySQL DBA 的操作,我思考了一下:为什么它直接就将GC保留的时间设置长了?

研究发现,MySQL的闪回是通过本地保存binlog日志实现的,且MySQL中,事务的一致性读是通过undo log实现的,所以这里并不会显著的影响正常数据的查询。

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

MySQL在进行mvcc控制的时候,读取历史的版本依赖的是:事务开始时间戳、当前的数据、undo log日志链。

在事务中在读取历史版本数据时,会先找到最新的数据,依靠每行数据自带的回滚指针,去undo log 中找到事务开始时间戳前最近的一个版本,按时间有序的链表查找历史数据

而在TiDB中,所有的dml操作都转化为在磁盘中进行追加一行新的数据,最新的数据和历史版本的数据都保留在一起了。

在读取数据时,会先将附近版本的数据全部读取,再根据所需版本进行过滤,这样当保留了过多版本的历史数据时,每次读取都会读取很多无用的数据,造成性能开销。

TiDB中历史版本过多问题及排查方法

在前面的推文中,我们分享过一期关于历史版本过多的排查方法,比较直观的描述了历史版本数据过多时,对于SQL执行直接的影响,大家有兴趣的可以回看→《一次TiDB GC阻塞引发的性能问题分析》

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中出现了性能问题,主要有如下:


# 1 偶发性的复杂SQL的连接算子不合理

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

解决方案:绑定执行计划,此方案对应用代码没有侵入性,且方便快捷。

# 2 SQL执行逻辑不佳

在部分复杂SQL中,在不影响SQL最终结果的前提下,先过滤计算某一部分结果作为临时表,会使整个sql的效率提高。

在部分场景中,MySQL优化器能自动优化处理,TiDB的执行计划不太合理。

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

# 3 部分小bug

这种问题通常指某些SQL导致的异常行为,多在后续版本中被修复了。例如某些场景下index hash join算子会存在一些问题,通过hint其他算子可绕过。

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

热点问题

相比于单机的MySQL数据库,分布式TiDB优势之一就是可以利用分布式集群多机器的能力,来突破单机的瓶颈。

但在某些时候,由于数据分布不合理,或者是业务专一的访问某一小部分的数据,这种时候可能会导致分布式集群中单机的瓶颈成为整个集群的瓶颈,这就是热点问题

热点的排查与解决

通常我们排查热点最常见的方法就是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.*.* -P4000 -uroot -p* -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

当然也可以通过调整系统参数实现。

大范围热点处理

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

排查与解决方案:

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

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

写在最后

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

关于今天的迁移干货分享就到这里了,欢迎大家一起交流~

从MySQL上面迁移到TiDB

常见问题与解决方案

你学习到了吗?

如果你有更好的办法或疑问

欢迎加入社群一起讨论哦⬇


本期作者

陈卓敏


原文链接: http://mp.weixin.qq.com/s?__biz=Mzg5MzUyOTgwMQ==&mid=2247517309&idx=1&sn=9cd67548e31eef4d3392fb8c89bf029e&chksm=c02fbfdbf75836cdaf2f6f08daeb96e66036a059b0e98f540d121a8bee6ae2d975a821f6d0b6#rd