了解一下Mysql的刷脏以及如何合理刷脏
mysql数据库跑着跑着突然有那么几秒或者十几秒所有的sql都不响应,就好像是所有的表被锁住一样,但是实际上都没有加锁。但会发现数据库卡几秒,磁盘IO很高,在疯狂地读写盘,其实此时mysql正在刷脏页。
什么是脏页?
Innodb在更新数据时,只更新了内存的数据页,但并没有更新磁盘。看下图
把数据页从磁盘读到内存,然后在内存里把行记录数据页修改,但mysql真实的数据并没有写回磁盘,就比如修改PPT,但没有ctrl+s,没保存,那么相当于内容在内存里,没有写回磁盘,但为什么能持久化,是因为redo log,redo log能在崩溃的时候重放内存中的数据页。假如内存没写回磁盘,内存中的数据和磁盘里的数据不一样,那么这种数据不一致的情况成为脏页。
什么是刷脏?
将内存中的数据页保存到磁盘,假如你修改过了ppt,按ctrl+s保存,那么就等于刷脏。mysql,刷脏的同时会删除相关的redo log。
为什么要刷脏?
- 内存中的脏页太多,内存不足
- redo log文件写满了,不能接收数据日志更新了,写不进去所以卡住
- 系统空闲的时候提前刷脏,预防上述情况
- mysql正常关闭前,保存数据,非kill
如何预防被迫刷脏?
正确告知Innodb服务器的磁盘性能。因为Innodb刷脏的速度跟磁盘性能有关的,如果磁盘很垃圾,告诉innodb磁盘很垃圾,innodb会慢慢的刷,因为刷快了磁盘受不了,导致性能更差
合理配置脏页比例上线,就好比设置内存可以设置多少脏页
控制刷脏策略
服务器IO配置
配置项:innodb_io_capacity,设置跟io性能相关的配置项,用来告知服务器的硬盘性能,决定刷脏速度。
了解一下IOPS:常见硬盘IOPS
- 台式机笔记本相关的7200转rpm SATA 的IOPS一般在70-100多,性能好的在100多,也就是每秒多少次IO;
- 服务器一般是10000 rpm FC的125的IOPS;
- SSD 固态硬盘SATA,大概在3000-40000的IOPS;
刷脏过慢的话 ,会浪费你的磁盘性能,所以要合理设置。
在配置之前先测试一下服务器的性能,测试命令如下(服务器假如没有fio,可以yum安装)
fio -filename=iotest_file -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10 -group_reporting -name=mytest
[root@S859680 ~]# fio -filename=iotest_file -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10 -group_reporting -name=mytest
mytest: (g=0): rw=randrw, bs=(R) 16.0KiB-16.0KiB, (W) 16.0KiB-16.0KiB, (T) 16.0KiB-16.0KiB, ioengine=psync, iodepth=1
...
fio-3.7
Starting 10 threads
mytest: Laying out IO file (1 file / 500MiB)
Jobs: 10 (f=10): [m(10)][100.0%][r=50.6MiB/s,w=50.6MiB/s][r=3239,w=3239 IOPS][eta 00m:00s]
mytest: (groupid=0, jobs=10): err= 0: pid=17915: Mon Oct 25 15:06:45 2021
read: IOPS=2489, BW=38.9MiB/s (40.8MB/s)(389MiB/10003msec) //读的位置
clat (usec): min=127, max=439291, avg=1988.97, stdev=4806.49
lat (usec): min=128, max=439292, avg=1990.94, stdev=4806.58
clat percentiles (usec):
| 1.00th=[ 165], 5.00th=[ 192], 10.00th=[ 215], 20.00th=[ 262],
| 30.00th=[ 310], 40.00th=[ 367], 50.00th=[ 529], 60.00th=[ 2024],
| 70.00th=[ 2835], 80.00th=[ 3654], 90.00th=[ 4752], 95.00th=[ 5735],
| 99.00th=[ 8225], 99.50th=[ 10290], 99.90th=[ 28705], 99.95th=[ 64226],
| 99.99th=[208667]
bw ( KiB/s): min= 95, max= 6336, per=10.00%, avg=3982.64, stdev=1188.00, samples=199
iops : min= 5, max= 396, avg=248.87, stdev=74.28, samples=199 //注意这里,这里是要设置到参数里的,平均大概250
write: IOPS=2508, BW=39.2MiB/s (41.1MB/s)(392MiB/10003msec) //写的位置
clat (usec): min=116, max=232175, avg=1972.94, stdev=5096.18
lat (usec): min=118, max=232177, avg=1975.68, stdev=5096.29
clat percentiles (usec):
| 1.00th=[ 155], 5.00th=[ 178], 10.00th=[ 196], 20.00th=[ 241],
| 30.00th=[ 289], 40.00th=[ 338], 50.00th=[ 441], 60.00th=[ 1975],
| 70.00th=[ 2769], 80.00th=[ 3621], 90.00th=[ 4752], 95.00th=[ 5669],
| 99.00th=[ 8029], 99.50th=[ 10421], 99.90th=[ 29230], 99.95th=[ 70779],
| 99.99th=[221250]
bw ( KiB/s): min= 32, max= 6784, per=9.99%, avg=4011.59, stdev=1223.41, samples=199
iops : min= 2, max= 424, avg=250.68, stdev=76.50, samples=199 //注意这里,这里是要设置到参数里的,平均大概250,
lat (usec) : 250=19.76%, 500=30.61%, 750=2.38%, 1000=0.73%
lat (msec) : 2=6.52%, 4=23.75%, 10=15.71%, 20=0.40%, 50=0.06%
lat (msec) : 100=0.03%, 250=0.04%, 500=0.01%
cpu : usr=0.88%, sys=4.68%, ctx=91997, majf=0, minf=13
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=24904,25095,0,0 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs):
READ: bw=38.9MiB/s (40.8MB/s), 38.9MiB/s-38.9MiB/s (40.8MB/s-40.8MB/s), io=389MiB (408MB), run=10003-10003msec
WRITE: bw=39.2MiB/s (41.1MB/s), 39.2MiB/s-39.2MiB/s (41.1MB/s-41.1MB/s), io=392MiB (411MB), run=10003-10003msec
Disk stats (read/write):
vda: ios=25084/25090, merge=1/10, ticks=16025/6698, in_queue=21191, util=85.33%
综合来看读写平均大概250,那么设置250就好了
配置合理的脏页比例上限
配置项:innodb_max_dirty_pages_pct
也就是说,磁盘里的页的数量和内存中脏页的数量比值,不能太高也不能太低。就好比我磁盘里有100个PPT,内存中打开了50个,假如设置了50%,内存中打开了50个PPT,假如你再打开一个,它会强制你把前面一些PPT保存并关掉,要不然脏页比例太多,如果突然有一个大请求,就没法搞了。当脏页比例接近此值的时候,会加速刷脏页,假如默认值是75,如果接近75%那么会把之前的脏页给保存到硬盘就可以达到提前刷脏的目的,不会在高峰期突然来的时候搞得很狼狈
控制”顺便刷脏“策略
配置项:innodb_flush_neighbors(SSD要关掉,不然会影响SSD的随机刷脏策略)
传统的机械磁盘连续写型能最好,尽量刷连续的页
SSD建议设置为0(8.0默认是0)