12 | 为什么我的MySQL会“抖”一下?

一条 SQL 语句,正常快,有时特别慢,难复现,随机持续时间短。


一、SQL 语句为什么变

第 2 篇文章介绍 WAL 机制。InnoDB 更新时,写日志(redo log重做日志)这个磁盘操作。酒店记账粉板,更新内存写完redo log 返回给客户端,更新成功。

掌柜记忆是内存更新账本,内存里写入磁盘 flush。flush前,赊账总额和账本记录不一致。今天赊账只在粉板。

不一致时,内存页为脏页。一致,为干净页

原来欠 10 文,又赊 9 文。

图 1 “孔乙己赊账”更新和flush 过程  

MySQL “抖”瞬间,可能就是刷脏页(flush):将内存页写入磁盘。

二、什么情况会引发数据库 flush?

1、粉板满了,再有赊账,放下手里活儿,粉板记录擦掉一些,继续记。擦掉前记账本。redo log 写满,停止更新,checkpoint 往前推,redo log留空继续写。

图 2 redo log 状态图

checkpoint 不是随便往前修改位置就可以。从 CP 推到 CP’,两点之间日志,所有脏页 flush 磁盘。write pos 到 CP’可再写。

2.生意太好记不住了,找账本把孔乙己这笔账先加进去1)写binlog

内存不足,需新内存页,内存不够用,淘汰数据页。如果淘汰“脏页”,先将脏页写磁盘2)写磁盘,空出内存

内存直接淘汰掉,下次从磁盘读入数据页,拿 redo log 出来应用不就行?性能考虑如果刷脏页一定写盘,保证数据页两种状态

(1)内存里存在,直接返回

(2)内存没有数据,文件上肯定是正确,读入内存后返回(效率高)。

3.生意不忙,更新账本。MySQL“空闲”刷“脏页”

4.年底结账。MySQL 正常关闭脏页flush 到磁盘上,下次启动直接从磁盘上读,快。

四种场景对性能影响

三、四不会太关注“性能”。

(1)redo log , InnoDB 尽量避免。系统不能更新,监控上看,更新数跌为 0。

(2)内存不够用,常态InnoDB 缓冲池(buffer pool)中的内存页有三种状态:

    没用; 用了干净页; 用了脏页。

策略:尽量使用内存,长时间运行库,未被使用页很少。

要读入数据页没在内存,到缓冲池申请。从内存中淘汰数据页(最久不用):干净页,释放复用脏页到磁盘,变干净复用

刷脏页也会影响性能,控制脏页比例,避免:

1. 淘汰脏页太多,响应时间明显变

2.  日志写满更新堵住,写性能 0。

三、InnoDB 刷脏页的控制策略

告诉 InnoDB 所在主机的 IO 能力知道全力刷脏页速度

innodb_io_capacity 设置成磁盘的IOPS(用于计算机存储设备,如硬盘(HDD)、固态硬盘(SSD)或存储区域网络(SAN))性能测试的量测方式。

通过 fio工具测试磁盘随机读写命令

 fio -filename=$filename -direct=1 -iodepth 1  -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10  -group_reporting -name=mytest

没正确地设置innodb_io_capacity 参数,导致性能问题。MySQL 写慢,TPS 很低,数据库主机的 IO 压力不大:

主机磁盘SSD,innodb_io_capacity= 300。InnoDB 系统能力差,脏页生成速度还,脏页累积,影响性能

不能一直全力刷,还需服务用户请求。

3.1控制刷脏页速度,参考因素

刷太慢,1、脏页太多,2、redo log 写满

InnoDB 先单独算出两个数字:

1、根据当前脏页比例 M,算出0 ~100数字,计算数字伪代码:

多关注脏页比例,不要让它经常接近 75%

F1(M)

{

  if M>=innodb_max_dirty_pages_pct (脏页比例上限,默认75%)then

      return 100;

  return 100*M/innodb_max_dirty_pages_pct;

}

2、InnoDB 每次写日志序号,跟 checkpoint 序号差 = N。根据N 算出 0 ~100 数字,公式F2(N)。算法复杂,N 越大,算出值越大

 F1(M) F2(N) 取较大值为 Rinnodb_io_capacity 乘以 R% 控制刷脏页的速度。

 F1、F2 通过脏页比例 redo log 写入速度算出来的两个值。

图 3 InnoDB 刷脏页速度策略

脏页比例:nnodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total 得到的,命令:

mysql> select  VARIABLE_VALUE into @a from global_status where VARIABLE_NAME =  'Innodb_buffer_pool_pages_dirty';

select  VARIABLE_VALUE into @b from global_status where VARIABLE_NAME =  'Innodb_buffer_pool_pages_total';

select @a/@b;

3.2有趣的策略:

查询请求需先 flush 掉脏页,比平时慢。MySQL一个机制,让查询更慢:刷脏页时,旁边是脏页,“邻居”一起刷掉;相邻还是脏页一起刷。

innodb_flush_neighbors控制这个行为,= 1“连坐”机制,= 0 不找邻居(默认)

找“邻居”机械硬盘(随机 IOPS 几百)时代有意义,减少很机 IO。相同逻辑减少随机 IO 性能提升。

SSD 这类 IOPS 高的设备,innodb_flush_neighbors = 0。 IOPS 不是瓶颈“只刷自己”更快。

小结

WAL 的概念(延续第 2 篇中介绍)

解释这个机制后续需要刷脏页操作和执行时机

WAL 技术,数据库将随机写转换成顺序写,大大提升数据库性能

内存脏页问题:脏页会被后台线程自动 flush,也由于数据页淘汰触发 flush,刷脏页过程占用资源,可能让更新和查询语句响应时间长。介绍了控制刷脏页方法监控方式

思考题

内存128GB、innodb_io_capacity = 20000 大规格实例,正常建议将 redo log 设置成 4 个 1GB 的文件。

不慎将 redo log 设置成 1 个 100M 的文件,发生什么情况?为什么?

答:每次事务提交都写 redo log,设置小很快被写满,write pos 一直追 CP。停止所有更新,推进 checkpoint。

现象:磁盘压力很小,数据库出现间歇性性能下跌。

评论1

刷脏页对应redo log位置随机,redo log不同位置刷掉,redo log处理不是很麻烦?(合并间隙,移动位置?)

redo log优势:将磁盘随机转换成顺序写,这样不是redo log里随机读写么? 

答:刷脏页过程不用动redo log文件redo log“重放”时,数据页刷过,会识别跳过

评论2

redo log保证ACID的D。

1.脏页保存到磁盘,checkpoint往前推

2.redo log记录undo变化,undo log buffer持久化undo log

3.innodb_flush_log_at_trx_commit=0,内存redo log持久化到磁盘

4.redo log记录change buffer改变,要把change buffer purge到idb

连change buffer的优化也没意义了

以及merge change buffer.merge也是脏页,持久化到磁盘

上述都是占用系统I/O,影响DML,操作频繁,'抖'向过冬。

select查询时间相对会更快。脏页变少,不用淘汰,直接用干净页。宕机恢复,速度快,checkpoint很接近LSN,恢复数据页相对较少

评论3

抖动现象,问题:

1)Innodb_buffer_pool_pages_total百万级别,不像人为设置,怎么来?

2)Innodb_buffer_pool_pages_dirty4万多开始flush了,脏页比例75,远达不到的,ssd磁盘,innodb_io_capacity=200,可以高。flush触发条件,内存不够,redo log 满,这个场景是哪种情况呢

回复: 1)是innodb 数据页总,过百万正常,16K一个,Bufree pool size 16G 就是100万

2)io_capacity设太小

评论4

buffer pool里维护脏页列表,假设redo log 的 checkpoint 记录 LSN (日志序列号)= 10,内存中一干净页有修改LSN为12,大于 checkpoint 的LSN,写redo log同时该页也会被标记为脏页记录到脏页列表中,现内存不足,该页被淘汰刷到磁盘,LSN=12从脏页列表中移除,redo log推进checkpoint,到LSN=12log时,为干净页跳过。

评论5

redo log写满:redo log对应脏页flush,释放空间。问题:

1、脏页flush到磁盘上,接将脏页数据覆盖到对应磁盘上数据?是的

2、redo log断电重启,内存丢失,通过redo log数据恢复,redo log怎么释放空间?

重启了就从checkpoint 位置往后扫。 之前刷过盘, 不会重复应用redo log

评论6

如何判断数据页是否在内存当中

每页又编号。拿编号去内存看,没有,就去磁盘

你可能感兴趣的:(12 | 为什么我的MySQL会“抖”一下?)