目录
刷盘机制总览
mysql刷脏数据在写redo之后,逻辑跟oracle一致,checkpoint/commit->内存中的redo到redolog文件->内存中的脏数据到数据盘。
但是mysql多一个环节,就是把binlog从binlog cache写入到binlog文件中。binlog cache不是共享内存,是为每个client分配的私有内存,是mysql server管理的。而log buffer是共享内存,由innodb管理,属于innodb存储引擎内存。
innodb_flush_logxxx是可能指刷redo也可能指刷binlog
innodb_xx_dirty_page_xx或者innodb_xx_page_xx是指的刷脏页的参数(buffer pool的脏页刷到磁盘中)
刷日志最重要的参数有2个
1.innodb_flush_log_at_trx_commit刷log buffer的redo到log file中
2.sync_binlog刷binlog cache的事务到binlog文件中
两个参数的默认值都是1,表示提交即写log(redolog和binlog都写),也就是mysql日志双写。
落盘可以从3个方向分析
binlog:
binlogcache是server为每个客户端分配的内存池,事务未提交前的数据放入binlogcache,提交后写入binlog日志文件。刷binlog的重要参数就是sync_binlog,0表示关闭写binlog,1表示每次提交便写binlog到磁盘(默认),N(N>=2)表示binlog组提交,可能丢失数据。
redolog:
redo在内存中存放在logbuffer,redo写入logfile是顺序循环写的,所以会比data写快(data一般是离散写)。logbuffer的重要参数是innodb_flush_log_at_trx_commit。0表示每秒写入磁盘,可能会丢失事务;1表示每次提交就写入磁盘(默认);2表示提交或每秒写入磁盘,也不会丢失事务。
(oracle的redo从redologbuffer到redo logfile:每3秒;每有提交;切换日志;1/3满或1MB。可以看出mysql跟oracle的redo落盘机制很类似,只是细节有些区别)
data:
bufferpool中的有个change buffer,也就是”插入缓存“,缓存了二级索引的变更信息,通过合并写入二级索引减少离散IO以提高性能。
刷脏页一般发生在commit之后,redo和binlog提交之后。innodb可以根据脏页在bufferpool中的水位强制刷脏页。Adaptive Flushing根据数据库负载情况调整刷每秒应该刷多少脏页。
binlog、redolog、data刷盘详解
log buffer(innodb的,由存储引擎分配)
log buffer是缓存准备写入logfile的内存区,相当于oracle的redo log buffer
innodb_flush_log_at_trx_commit (刷redo的机制)
innodb事物提交的重要参数,取值只有0、1、2,默认为1,动态参数。
该参数是用来控制提交操作和高性能的,如果需要更高的性能,在crash时可能存在数据丢失风险,也就是不具备ACID的持久性。
0:log每秒写入磁盘。crash时可能会丢失数据(因为那些已提交完成的事物还没有落盘)
1:默认值是1,在事务提交时刷脏数据到盘
2:log每秒写入磁盘,且在每次提交时写入磁盘。此状态时也不会丢失数据。
(注意:“落盘”是磁盘返回给mysql的结果,但是磁盘也有缓存,数据写入磁盘缓存后,也会返回给数据库“已落盘”的信息。磁盘缓存取决于磁盘或磁盘整列的策略,磁盘阵列通常都有备用电池的,除非数据一致性极高的情况,一般都不会关闭磁盘或阵列的缓存)
(上面的“事物提交”不仅指commit,也包含checkpoint、ddl等,会触发“提交”的操作)
innodb_log_buffer_size
innodb_log_buffer_size:log buffer的大小,默认16M,最小1M,最大4G。
如果log buffer足够大,在事务提交之前,redolog就不需要写入logfile磁盘了。
innodb_log_write_ahead_size
动态参数,默认8k
write-ahead block就是指redo log page。redolog的page大小可以和innodb data page不一样,必须是操作系统块大小的整数倍,操作系统块一般默认是4K,redo log page默认是8k,innodb data page默认是16k。
binlog cache(由server分配)
binlog cache又server分配和管理,不是innodb。binlog cache是私有的,每个连接客户端都有。
sync_binlog(刷binlog机制)
binlog提交的重要参数。取值0、1、N(N>=2), 5.7.7及以上版本默认为1,5.7.7以下版本默认是0。动态参数。
注意跟innodb_flush_log_at_trx_commit 是不一样的,innodb_flush_log_at_trx_commit 控制的是buffer pool的redo到log file,取值仅0,1,2,含义也不一样。
0:关闭写binlog功能。
1:开启写binlog功能,在事务提交之前就同步binlog。这种模式下binlog不会丢失事务。默认情况、一般情况都是1。
N:开启binlog组提交, binary log commit groups。这种模式下可能丢失已提交但还未flush到binlog的事务。N越高,对性能提升越明显,丢失数据的风险也越高。
innodb_flush_log_at_trx_commit=1且sync_binlog=1,是mysql的默认和通用配置。redo和binlog各有用处,且保证了数据的持久性。
innodb_flush_log_at_timeout(binlog group commit)
group commit相关参数,只有打开group commit功能时才有效。
binlog group commit的时间间隔设置。
别搞混了,跟innodb_flush_log_at_trx_commit是2个参数,针对不同的log,虽然都是flush_log
binlog_group_commit_sync_delay
group commit相关参数,只有打开group commit功能时才有效。
事务提交之前同步binlog的延时。0表示没有延时,commit和写入binlog是同时的。如果设置该值,commit是有延时的。如果sync_binlog设置为>1,那么延时就是group commit的。
这参数看上去就是增加commit延时,应该不会有人开启这个功能吧。
binlog_group_commit_sync_no_delay_count
group commit相关参数,只有打开group commit功能时才有效。
延时时的最大事务数(group commit), binlog_group_commit_sync_delay为0时,这个参数也无效了。
binlog_cache_size
binlog cache的大小,默认32k。动态参数。
如果binlog开启,server会给每个client分配binlog cache。如果总有大事物,可以把该内存池调大。show global status中的有当前binlog cache使用信息。
binlog_stmt_cache_size
默认32k,动态参数。
binlog statment cache缓存在事务中的非事务性语句。如果binlog打开,且有事务性存储引擎,server会给每个client分配binlog cache和binlog statement cache。如果经常事务中有较大的非事务语句,调大此cache可以提升一定的性能,同样在show global status中有使用信息。
buffer pool
buffer pool是innodb引擎的重要内存结构,相当于oracle的数据库快速缓存区data buffer cache。
change buffer(以前叫插入缓存)是buffer pool的一部分,默认占用buffer pool size的1/4,存储变更的二级索引信息。因为变更的二级索引落盘一般都是随机IO,二级索引合并后写入,可以减少随机IO的负担,这就是changebuffer存在的意义。
buffer pool还有一些其他功能和要点,比如LRU,预读read-ahead,预留resistant,预热Saving and Restoring,子池,监控等等。buffer pool详情解读:buffer pool内存结构和相关运行机制
https://blog.csdn.net/qq_40687433/article/details/111994959
这次重点分析刷脏页
innodb buffer pool除了加载select的page到buffer pool外,还需要刷脏数据。脏数据就是在内存已被修改,但是仍未写入磁盘的数据。
innodb_flush_method
Command-Line Format | --innodb-flush-method=value |
System Variable | |
Scope | Global |
Dynamic | No |
Type | String |
Default Value | NULL |
Valid Values (Windows) | async_unbuffered normal unbuffered |
Valid Values (Unix) | fsync O_DSYNC littlesync nosync O_DIRECT O_DIRECT_NO_FSYNC |
如果是NULL,那么当系统是类unix时,默认为fsync,当系统是windows时,默认为async_unbuffered。
该参数是innodb的参数,影响刷buffer pool的脏数据和log buffer中的redo的方式。
类unix:
fsync:默认规则,使用fsync()刷data和log file。
O_DSYNC:使用O_DSYNC去打开和刷新log file,fsync()去耍data file。在某些unix场景可能不适用。
littlesync:内部参数,尽量不要使用
nosync:内部参数,尽量不要使用
O_DIRECT:使用O_DIRECT()打开数据文件,使用fsync()刷data和log file
O_DIRECT_NO_FSYNC:O_DIRECT()刷数据,忽略fync()请求
参数配置和最佳性能取决于mysql的环境,在确定使用哪种flush模式前应尽量充分的测试
从官方文档的innodb结构图看,O_DIRECT应该是不会过操作系统缓存,fsync应该就是要过OS cache。mysql官网对这个描述不多。先放着,下次研究IO的。
(mysql IO调度机制:https://liuzhilong.blog.csdn.net/article/details/114670467)
innodb_page_cleaners
innodb_page_cleaners是清理脏数据线程的个数,在mysql5.7中清理线程默认是4个。当innodb_page_cleaners大于等于innodb_buffer_pool_instances时,innodb_page_cleaners会被自动设置为innodb_buffer_pool_instances相等的值。
innodb_max_dirty_pages_pct_lwm
脏页的最低水位,默认为0,非0时表示开启脏页预刷,当脏页达到innodb_max_dirty_pages_pct_lwm时刷脏页就开始了
innodb_max_dirty_pages_pct
innodb_max_dirty_pages_pct控制脏页在buffer pool中的百分比,默认是75,innodb就会强制刷脏页。
innodb_flush_neighbors
innodb_flush_neighbors刷一个脏page时,是否刷这个page的整个extent。0表示关闭该功能,1表示刷extent中连续的pages(默认),2表示刷整个extent中的pages。当数据在普通盘上,开启该功能可以减少IO次数,而不是在不同的时间刷page,当数据在ssd上,IO情况较好,可以考虑关闭该功能,刷整个extent会比刷一个page更慢。mysql8.0中innodb_flush_neighbors的默认值为0
innodb_lru_scan_depth
innodb_lru_scan_depth在每个buffer pool子池中扫描LRU链的脏数据刷到磁盘的深度,找到的这些脏块就会flush,后台清理线程每秒执行一次。depth越小,对性能越有利,仅当IO有空余时才考虑增大depth的值。当IO特别繁忙,特别是buffer pool很大时,可以考虑适当调小depth。cleaner线程每秒会跑 innodb_lru_scan_depth * innodb_buffer_pool_instances
自适应刷脏页Adaptive Flushing
自适应刷脏页算法可以自动调节刷脏页的频率,频率取决于redo的生成和当前刷脏页的频率
该算法的目的就是让刷脏页的频率能赶上当前数据库的负载情况。自适应刷脏页会自动判断每秒应该刷多少脏页。
在mysql内部测试中发现,自适应刷脏页并不是在所有场景中都有性能提升,但是在redo log快满的时候,有较大的效果
Sharp checkpoints,在innodb想reuse一个log file时触发,会产生大量的redo条目,这些redo需要写到redolog中。logfile中之前的redo会被清空,当redo满后就会触发Sharp checkpoints,即时没有达到innodb_max_dirty_pages_pct的值。
innodb_adaptive_flushing
开启自适应刷脏页,默认开启。
innodb_adaptive_flushing_lwm
是redo log的最低水位(low water mark),当达到这个值,即时innodb_adaptive_flushing是关闭的,也会触发自适应刷脏页
innodb_flushing_avg_loops
保留之前flush动作的资源快照信息。innodb_flushing_avg_loops越高,说明保留的计算资源时间越长,自适应刷脏页也就越慢