从上图中,我们可以看到,数据InnoDB到磁盘需要经过
这里我们使用术语“缓冲”(一般为buffer)来表示对数据写的暂存,使用术语“缓存”(一般为cache)来表示对数据读的暂存。顾名思义,由于底层存储设备和内存之间速率的差异,缓冲是用来暂“缓”对底层存储设备IO的“冲”击。缓存主要是在内存中暂“存”从磁盘读到的数据,以便接下来对这些数据的访问不用再次访问慢速的底层存储设备。
RDS的几个参数的默认情况 innodb_flush_method = O_DIRECT innodb_flush_log_at_trx_commit = 1 innodb_flush_log_at_timeout = 1
该层的缓冲都放在主机内存中,它的目的主要是在应用层管理自己的数据,避免慢速的读写操作影响了InnoDB的响应时间。
InnoDB层主要包括两个buffer:redo log buffer和innodb buffer pool。
redo log buffer用来暂存对重做日志redo log的日志写,InnoDB buffer pool存储了从磁盘设备读到的InnoDB数据,也缓冲了对InnoDB数据写,即脏页数据。
如果主机掉电或者MySQL异常宕机,innodb buffer pool将无法及时刷新到磁盘,那么InnoDB就只能从上一个checkpoint使用redo log来前滚,(pg也是redolog)而redo log buffer如果不能及时刷新到磁盘,那么由于redo log中数据的丢失,就算使用redo前滚,用户提交的事务由于没有真正的记录到非易失型的磁盘介质中,就丢失掉了。
控制redo log buffer刷新时机的参数是innodb_flush_log_at_trx_commit,而控制redo log buffer和innodb buffer pool刷新方式的参数为innodb_flush_method。针对这两个参数详细介绍的文章有非常多,我们这里主要从缓冲的角度来解析。
控制redo log buffer的innodb_flush_log_at_trx_commit目前支持3种不同的参数值0,1,2
< 5.6.6: 每隔一秒将redo log buffer中的数据刷新到磁盘
= 5.6.6:每隔innodb_flush_log_at_timeout秒将数据刷新到磁盘中去。
NOTES:
控制innodb buffer pool的innodb_flush_method目前支持4种不同的参数值:
汇总
Open log | open log | flush log | Open datafile | flush datafile |
---|---|---|---|---|
fdatasync | fsync() | fsync() | ||
O_DSYNC | O_SYNC | fsync() | ||
O_DIRECT | fsync() | O_DIRECT | fsync() | |
O_DIRECT_NO_FSYNC | fsync() | O_DIRECT | ||
All_O_DIRECT(percona) | O_DIRECT | fsync() | O_DIRECT | fsync |
Notes:
fsync
: InnoDB
uses the fsync()
system call to flush both the data and log files. fsync
is the default setting.
fsync数据和日志都不绕过OS的缓冲区
O_DIRECT
: InnoDB
uses O_DIRECT
(or directio()
on Solaris) to open the data files, and uses fsync()
to flush both the data and log files. This option is available on some GNU/Linux versions, FreeBSD, and Solaris.
数据绕过os缓冲,日志不绕
O_DIRECT_NO_FSYNC
: InnoDB
uses O_DIRECT
during flushing I/O, but skips the fsync()
system call after each write operation.
数据绕过os缓冲,不sync,日志不绕
什么是fsync和o_direct?
写盘分三个动作:
[1] open 打开文件
[1] write 写文件(和open绑定)
[2] flush flush操作(将文件缓存刷到磁盘上)
open("test.file",O_WRONLY|O_APPDENT|O_SYNC))
我们打开一个文件并写入数据,VFS和文件系统是怎么把数据写到硬件层列,下图展示了关键的数据结构:
https://www.usenix.org/legacy/event/usenix01/full_papers/kroeger/kroeger_html/node8.html
根据文件系统和操作系统的不同,一般来说对一个文件的写入操作包括两部分,对数据本身的写入操作,以及对文件属性(metadata元数据)的写入操作(这里的文件属性包括目录,inode等)。
page cache | buffer cache | inode cache | dictory cache | |
---|---|---|---|---|
O_DIRECT | write bypass | write bypass | write & no flush | write & no flush |
O_DSYNC/fdatasync() | write & flush | write & flush | write & no flush | write & no flush |
O_SYNC/fsync() | write & flush | write & flush | write & flush | write & flush |
回过头来,我们再来看innodb_flush_log_at_trx_commit的配置就比较好理解了。
O_DIRECT直接IO绕过了page cache/buffer cache以后为什么还需要fsync()了,就是为了把directory cache和inode cache元数据也刷新到存储设备上。
而由于内核和文件系统的更新,有些文件系统能够保证保证在O_DIRECT方式下不用fsync()同步元数据也不会导致数据安全性问题,所以InnoDB又提供了O_DIRECT_NO_FSYNC的方式。
在大部分的innodb_flush_method参数值的推荐中都会建议使用O_DIRECT,甚至在percona server分支中还提供了ALL_O_DIRECT,对日志文件也使用了O_DIRECT方式打开。
优势
劣势
/sys/block/sda/queue/logical_block_size
知道对齐的大小,一般都是512个字节。page cache/buffer cache
直接写存储设备,这样如果对同一块数据进行重复写就无法在内存中命中,page cache/buffer cache
合并写的功能就无法生效了。https://www.kernel.org/doc/Documentation/filesystems/ext4.txt
data= journal
All data are committed into the journal prior to being
written into the main file system. Enabling this mode will
disable delayed allocation and O_DIRECT support.
data= ordered (*)
All data are forced directly out to the main file
system prior to its metadata being committed to the journal.
data= writeback
Data ordering is not preserved, data may be written
into the main file system after its metadata has been
committed to the journal.
该层的缓冲都放在存储控制器的对应板载cache中,它的目的主要是在存储控制器层缓冲数据,避免慢速块设备读写操作影响了IO的响应时间。
当数据被fsync()等刷到存储层时,首先会发送到存储控制器层。常见的存储控制器就是Raid卡,而目前大部分的Raid卡都有1G或者更大的存储容量。这个缓冲一般为易失性的存储,通过板载电池/电容来保证该“易失性的存储”的数据在机器断电以后仍然会同步到底层的磁盘存储介质上。
关于存储控制器我们有一些几个方面需要注意的:
该层的缓冲都放在磁盘控制器的对应板载cache中。存储设备固件(firmware)会按规则排序将写操作真正同步到介质中去。这里主要是保证写的顺序性,对机械磁盘来说,这样可以尽量让一次磁头的移动能够完成更多的磁碟写入操作。
一般来说,DMA控制器也是放在磁盘这一层的,通过DMA控制器直接进行内存访问,能够节省CPU的资源。
对于机械硬盘,因为一般的磁盘设备上并没有电池电容等,无法保证在机器掉电时磁盘cache里面的所有数据能够及时同步到介质上,所以我们强烈建议把disk cache关闭掉。
从InnoDB到最终的介质,我们经过了各种缓冲,他们的目的其实很明确,就是为了解决:内存和磁盘的速度不匹配的问题,或者说是磁盘的速度过慢的问题。
另外,其实最懂数据是否应该缓冲/缓存的还是应用本身,VFS,存储控制器和磁盘只能通过延迟写入(以便合并重复IO,使随机写变成顺序写)来缓解底层存储设备慢速造成的响应速度慢的问题。所以数据库类型的应用都会来自己管理缓冲,然后尽量避免操作系统和底层设备的缓冲。
但是其实由于目前SSD固态硬盘和PCIe Flash卡的出现,内存和磁盘之间的速度差异被大大缩减了,这些缓冲是否必要,软硬件哪些可改进的,对软硬件工程师的一大挑战。
https://www.ibm.com/developerworks/cn/linux/l-anatomy-ext4/index.html
https://www.cnblogs.com/DataArt/p/10229913.html
http://en.wikipedia.org/wiki/Disk_buffer
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Storage_Administration_Guide/writebarrieronoff.html
http://en.wikipedia.org/wiki/Direct_memory_access
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有