揪出MySQL延迟上千秒的元凶
背景
MySQL的延迟告警想必大家一定不陌生,MySQL引起从库延迟的原因有很多,从硬件上讲可能是网卡,磁盘,内存达到瓶颈,从数据库层面来讲,可能是SQL效率低下,或者大批量写入引起的。本文的案例将剖析一个由binlog格式引发的延迟问题,看完本文,再遇到这类告警的时候,相信你可以瞬间定位到问题所在!
binlog_format
--binlog-format=format
binlog_format
Global, SessionYes (>=5.5.31-ndb-7.2.13)enumeration (>=5.5.15-ndb-7.2.1, <=5.5.30-ndb-7.2.12)enumerationenumeration (>=5.5.31-ndb-7.2.13)MIXED
(>=5.5.15-ndb-7.2.1, <=5.5.30-ndb-7.2.12)STATEMENT
STATEMENT
(>=5.5.31-ndb-7.2.13)ROW
STATEMENT
MIXED
ROW
STATEMENT
MIXED
ROW
STATEMENT
MIXED
众所周知,binlog_format是设置binlog格式的参数,我们可以配置为STATEMENT、MIXED、ROW三种格式,可以动态调节。三种格式各有有缺。我们的线上生产库统一配置的是MIXED格式。MIXED格式会在STATEMENT格式和ROW格式中根据场景不同来使用不同的格式进行切换。
mysql> show global variables like 'binlog_format'; + - - - - - - - - - - - - - - - - - - - - - - - - - + | |,Variable_name Value | + - - - - - - - - - - - - - - - - - - - - - - - - - + | |,binlog_format MIXED | + - - - - - - - - - - - - - - - - - - - - - - - - - + 1,row set 拷贝;(0.08,sec)
<强> 强>
对于混合格式来说,在如下情况的时候,binlog会自动转为行格式记录
1. ndb引擎
2. sql语句里包含了UUID()函数。
3。自增长字段被更新了。
4。包含了插入延迟语句。
5。使用了用户定义函数(UDF) .
6。使用了临时表。
7。?还有一种情况会导致mixed格式转换为ROW,本文会加以复现。
实战
我们看出,在凌晨2点的时候,从库的延迟陡增,而此时从库的机器负载和网卡并未达到瓶颈。
我们可以看出,从2点06起,binlog刷新非常快,基本上几十秒就可以写满一个1.1GB的binlog文件。这样基本就能够确定,是因为写入量过大导致的。
写入量过大又有两种情况:
单纯的业务量激增,QPS增长引起;
binlog转为了ROW格式导致存储内容激增引起。
我们使用pt工具pt-query-digest或者命令行,都能够分析出binlog做了哪些操作。使用pt-query-digest的话可以结合mysqlbinlog命令,对日志进行分析。
delete from tablename where xxxx limit 100;
这种语法会将MIXED格式的binlog,转为ROW格式记录,而笔者案例中的这张表包含TEXT大字段,每次delete都会把整个TEXT大字段带入binlog,进而导致binlog激增,从库追不上主库产生延迟的情况。
根本原因找到后,解决起来就得心应手了,找到相关开发,去掉delete from table where xxx limit 这种用法,就能够避免row格式的记录。
其实,delete/update limit、insert .....select limit这种用法是危险的,很容易产生问题。真的要使用这种这种方法的话,也需要结合order by语句来保证limit的有效性。
遇到此类语句时:
当使用STATEMENT模式时,会发出一个警告,说明语句对于基于语句的复制是不安全的。