版本:mysql 8.0.19
一、IO基础知识
首先在理解参数innodb_flush_method含义之前,先需要了解linux中文件打开的方式,即O_DIRECT,O_SYNC。简单来说,其含义如下:
- O_DIRECT:无缓冲的输入、输出,应用程序在执行磁盘IO时绕过缓冲区高速缓存,从用户空间直接将数据传递到文件或磁盘设备,称为直接IO(direct IO)或者裸IO(raw IO);
- O_SYNC: 使用内核缓冲区,不过采用同步IO的方式进行读写,也就是每次io系统调用后都等待实际的物理I/O完成才放回。
下面是计算机io数据流
从图中可以知道:一般应用程序进行io操作会经过:
- 应用buffers,比如mysql服务端读取命令的buffers,在没有读取到命令结束符之前,都需要应用端缓存之前收到的命令;
- 库buffers,比如标准io库内部就有自己的库buffers,当缓存满时才进行真正写盘操作;
- 内核buffers,其主要就是系统为了减少读盘次数以及写盘次数,而上面所说的flag(O_DIRECT,O_SYNC)也就是说该buffers的。
- O_DIRECT模式就是不使用内核buffers,用户数据直接写入磁盘;
- O_SYNC模式使用内核buffers,不过每次write操作都需要强制刷新内核缓冲区到输出文件才返回。
问题1:O_SYNC与fsync系统调用的区别?
O_SYNC是每次write系统调用后都等待实际的物理I/O完成。而fsync也是会等待物理I/O完成后才返回。也就是说:O_SYNC会一直起作用,而fsync(或者fdatasync)是一次性的操作。
问题2:fsync,fdatasync,sync系统调用有什么区别?
在回答这个问题之前,首先要明白磁盘中文件包含文件的元数据和文件内容,通常我们读写的是文件的内容,但是我们不能忽略其元数据。如果两种不一致也会导致文件丢失或者损坏,并且两者一般不会保存在同一数据块中,所以进行写盘操作不仅要保证文件内容持久化,也需要保证文件的元数据持久化(当然有时候修改文件内容,元数据不一定改变,此时只需要持久化数据内容即可)。
明白了上面的内容就很好理解fsync,fdatasync,sync这三个系统调用了
- fsync:对指定文件句柄的数据以及元数据都进行刷盘操作,并且等待完成,然后返回;
- fdatasync:仅对指定文件句柄的数据进行刷盘操作,等待完成并放回。这里并没有同步进行元数据刷盘操作,可能有不一致现象;
- sync:将所有修改过的块(并不针对特定文件)缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。通常称为update的系统守护进程会周期性地(一般每隔30秒)调用sync函数。这就保证了定期冲洗内核的块缓冲区。
二、innodb_flush_method参数含义
innodb_flush_method参数是控制innodb引擎进行数据以及日志磁盘刷盘方式的参数,这是一个非动态参数,如果需要修改则必须重启服务器。
首先我们来看一下该参数有哪些值,也可以通过number指定,以及各种不同值(unix环境)的含义。
值 | 含义 |
---|---|
fsync(0,默认) | 表示innodb会使用fsync函数为数据以及日志刷盘 |
O_DSYNC (1) | innodb对于日志文件和数据文件采用不同策略:日志文件使用O_SYNC方式打开,保证每次写入都内刷盘;数据文件使用fsync系统调用进行主动刷盘操作。 |
littlesync (2)nosync (3) | 用于内部性能测试,用户尽量不要使用,自己承担风险 |
O_DIRECT (4) | innodb使用O_DIRECT方式读写数据文件,当io完成时都使用fsync对数据和日志文件进行刷盘 |
O_DIRECT_NO_FSYNC | 该级别与O_DIRECT类似,都是使用O_DIRECT方式进行数据文件读写,但是并不是每次读写都调用fsync进行刷盘。 |
级别从下到上越来越严格,因此性能也越低。因为fsync操作是一个比较耗时操作,减少这种操作可以提高性能,所以从fsync到O_DIRECT再到O_DIRECT_NO_FSYNC,性能会有明显提升。
问题3:为什么使用了O_DIRECT,依然需要调用fsync?
这是因为O_DIRECT模式进击保证了数据持久化,但是元数据依然没有持久化,故存在数据丢失可能
问题4:为什么还有O_DIRECT_NO_FSYNC级别?
由于并不是每个数据操作都会造成元数据改变,所以有时候不需要再调用fsync了。
如果能够区分这些不同的IO操作类型,以区别对待是否修改了元数据的操作,那么就可以提升IO性能。以下是官方说明:
Prior to MySQL 8.0.14, this setting is not suitable for file systems such as XFS and EXT4, which require an fsync()
system call to synchronize file system metadata changes. If you are not sure whether your file system requires an fsync()
system call to synchronize file system metadata changes, use O_DIRECT
instead.
As of MySQL 8.0.14, fsync()
is called after creating a new file, after increasing file size, and after closing a file, to ensure that file system metadata changes are synchronized. The fsync()
system call is still skipped after each write operation.
Data loss is possible if redo log files and data files reside on different storage devices, and a crash occurs before data file writes are flushed from a device cache that is not battery-backed. If you use or intend to use different storage devices for redo log files and data files, and your data files reside on a device with a cache that is not battery-backed, use O_DIRECT
instead.
从说明上可以看到:从MySQL 8.0.14开始,社区版本就已经为我们做了区分不同操作是否修改元数据的判断。因此,现在O_DIRECT_NO_FSYNC是可以取代O_DIRECT的。(只是如果日志文件和数据文件再不同存储设备上,还是建议使用O_DIRECT)
If
innodb_dedicated_server
s enabled, theinnodb_flush_method
value is automatically configured if it is not explicitly defined.
如果开启了innodb_dedicated_server
,则服务器会自动选择其配置。从测试结果看,使用O_DIRECT_NO_FSYNC性能至少提升了20%+。