MYSQL 脏页刷新

起因

昨天看了CSDN推送的一篇《腾讯面试:一条SQL语句执行得很慢的原因有哪些?》

里面主要提到了
1.数据库在刷新脏页的时候会导致SQL很慢
2.锁的问题
3.sql本身的问题

下面主要对刷脏页理解,自己总结下

mysql 刷脏块的几种情况

1.redo日志切换

2.buffer pool不足

3.mysql 自己觉得空闲

4.mysql正常关机

上面的3,4两种情况可以忽略他们对性能的印象。

而 1,2两种情况都有可能会影响mysql整体的性能,其实两种情况的原因是一样的,刷脏页会占用大量的IO资源,会影响到你其他的sql。

第一种情况,redo写满了需要覆盖,覆盖前需要filush没有被写入磁盘的脏页,这种情况是要尽量的避免的,因为这种情况出现,整个系统会不在DML。在5.6之前可能还会阻塞查询。

第二中情况,内存不够了,需要为查询或者更新腾出对应的空闲页,这种情况很常见。

上面还会涉及很多的东西,比如检查点,LRU LIST,FLUSH LIST,FREE LIST .

影响

主要两个方面:

1.innodb_max_dirty_pages_pct

aac84db0f645dde6ffc4b8385d5a1a6e.png

2.innodb_io_capacity

3.innodb_adaptive_flushing(不建议关闭)

InnoDB uses an algorithm to estimate the required rate of flushing, based on the speed of redo log generation and the current rate of flushing. The intent is to smooth overall performance by ensuring that buffer flush activity keeps up with the need to keep the buffer pool “clean”. Automatically adjusting the rate of flushing can help to avoid sudden dips in throughput, when excessive buffer pool flushing limits the I/O capacity available for ordinary read and write activity.

InnoDB uses its log files in a circular fashion. Before reusing a portion of a log file, InnoDB flushes to disk all dirty buffer pool pages whose redo entries are contained in that portion of the log file, a process known as a sharp checkpoint. If a workload is write-intensive, it generates a lot of redo information, all written to the log file. If all available space in the log files is used up, a sharp checkpoint occurs, causing a temporary reduction in throughput. This situation can happen even if innodb_max_dirty_pages_pct is not reached.

上面的意思就是mysql会使用一个算法来根据磁盘的IO能力和脏页数量等来计算对脏页的刷新,当然在大量的写的情况下,影响性能也是不可避免的。

计算为:

根据当前脏页占比和Redo LSN增长状态,计算利用IO Capacity的百分比(pct_total)计算目标LSN:

根据当前脏页占比和Redo LSN增长状态,计算利用IO Capacity的百分比(pct_total)

计算目标LSN:

target_lsn = oldest_lsn + lsn_avg_rate * buf_flush_lsn_scan_factor

其中oldest_lsn表示当前buffer pool中最老page的LSN,lsn_avg_rate表示每秒LSN推进的平均速率,buf_flush_lsn_scan_factor目前是hardcode的,值为3。

统计每个buffer pool 小于target_lsn的page数pages_for_lsn

初步估定每个bp instance 的n_pages_requested= pages_for_lsn /buf_flush_lsn_scan_factor。每个bp的pages_for_lsn被累加到sum_pages_for_lsn

同时根据io capacity估算总的需要flush的Page数量:

sum_pages_for_lsn /= buf_flush_lsn_scan_factor;
n_pages = (PCT_IO(pct_total) + avg_page_rate + sum_pages_for_lsn) / 3;

n_pages若超过innodb_io_capacity_max,则设置为innodb_io_capacity_max

轮询每个Buffer pool 实例:
如果当前有足够的Redo 空间:n_pages_requested  = n_pages / srv_buf_pool_instances
否则:n_pages_requested = n_pages_requested  * n_pages / sum_pages_for_lsn
也就是说,在Redo 空间足够时,依然采用均衡的刷脏逻辑。

在早期版本中,会根据两个条件来判断每个bp刷脏的进度:目标LSN及page数。而到了5.7.6版本里,大多数情况下只根据更加准确的请求刷page数来进行判定 (系统空闲时进行100% io capactiy的page flush、崩溃恢复时、以及实例shutdown时的刷脏除外)

虽然计算公式比较清晰,但有些factor的定值依然让人很困惑,也许是官方测试的比较理想的配置。不过最好还是设置成可配置的,由有经验的用户根据自己具体的负载情况来进行定制

上面的innodb_io_capacity 参数也变得尤其重要。一般可以设置为磁盘的IOPS

还需要关注脏页的比例,(Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total)

mysql> select VARIABLE_VALUE from performance_schema.global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 12634             |
+----------------+
1 row in set (0.00 sec)

mysql> select VARIABLE_VALUE  from performance_schema.global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_total';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 655280         |
+----------------+
1 row in set (0.00 sec)

Page cleaner thread是5.6.2引入的一个新线程,它实现从master线程中卸下缓冲池刷脏页的工作;为了进一步提升扩展性和刷脏效率,在5.7.4版本里引入了多个page cleaner线程,从而达到并行刷脏的效果。
目前Page cleaner并未和缓冲池绑定,有一个协调线程 和 多个工作线程,协调线程本身也是工作线程。工作队列长度为缓冲池实例的个数,使用一个全局slot数组表示

参考:

http://mysql.taobao.org/monthly/2015/03/02/

你可能感兴趣的:(mysql)