InnoDB O_DIRECT选项漫谈(二)

前一篇中已经解释了InnoDB存储引擎为什么即使在开启O_DIRECT选项后依然需要调用fsync操作。本篇将说明MySQL 5.6中InnoDB存储引擎的变化以及O_DIRECT对重做日志文件的影响。

从MySQL 5.6的版本开始,也就是InnoDB 1.2版本中(PS:MariaDB 10.x版本将集成InnoDB 1.2版本),对于参数innodb_flush_method提供了一个新的设置值O_DIRECT_NO_FSYNC。在该参数设置下,InnoDB存储引擎将依然使用O_DIRECT选项打开数据表空间文件,但是在刷新时,不再需要需要额外的fsync操作。见官方手册中的说明:

An alternative setting is O_DIRECT_NO_FSYNC: it uses the O_DIRECT flag during flushing I/O, but skips thefsync() system call afterwards. This setting is suitable for some types of filesystems but not others. For example, it is not suitable for XFS. If you are not sure whether the filesystem you use requires anfsync(), for example to preserve all file metadata, use O_DIRECT instead.

然而,官方仅说明使用xfs文件系统不能设置为O_DIRECT_NO_FSYNC,但却只字未提哪个文件系统可以设置?请问MySQL官方这样的说明又有何意义呢?reiserfs和btrfs貌似(不十分确定)不使用inode来存放元数据信息,或许这两个文件系统下可以进行O_DIRECT_NO_FSYNC的设置?这个问题留给文件系统专家来回答了。不过目前看来,最为安全和稳妥的做法还是将参数innodb_flush_method设置为O_DIRECT。

继续深入思考一个问题,为什么InnoDB的重做日志不使用O_DIRECT标识进行打开,而依然使用buffered I/O呢?我的理解是为了更为有效的Group Commit。若深入源码内部来看事务提交时的操作,InnoDB存储引擎的处理方式:

lock log->mutex
copy last redo log block to a new block
write redo log buffer to disk
unlock log->mutex
fsync redo log files

可以看到fsync操作是在释放log->mutex之后。这样做的目的是在fsync时,由于已经释放log->mutex,那么其他事务可以继续将重做日志条目写入到redo log buffer中,同时这也是为什么在事务提交时,InnoDB会拷贝最后一个redo log block。若重做日志使用O_DIRECT,写入重做日志文件的过程会变慢(因为不是仅写入到操作系统缓存),Group Commit的效率就会变差。

Mark Callaghan尝试过以O_DIRECT的方式打开重做日志(http://www.facebook.com/note.php?note_id=10150219759210933),结果如下所示:

Results for all_direct are better at low-concurrency and O_DIRECT is faster for 4 or more concurrent connections.
1 2 4 8 16 32 64 128
1952 2777 3530 3755 3829 3741 3760 3803 all_direct
1608 2479 3507 4541 4550 4644 4698 4581 O_DIRECT

Mark Callaghan只是给出了测试的结果,但是并没有说明问题的原因。根据Mark的测试环境,我想这就是因为Group Commit效率问题所致。Percona版本提供了ALL_O_DIRECT来设置重做日志的打开标识,但是根据我的研究,这是没有必要的,用户也不需要过于迷信该参数。

MySQL 5.6开始InnoDB可以将重做日志文件组设置为最大512G,之前的限制为4G。这对SSD和写入密集型应用会带来明显的帮助。但是重做日志buffered I/O的问题是会导致使用过多的操作系统缓存,这也是为什么Mark会想到使用O_DIRECT的方式来打开重做日志。

既然不能在InnoDB内部处理该问题(至少目前),我想可以通过操作系统提供的接口来刷新操作系统中缓存的数据,从而减少内存过度的使用问题。例如:

sysctl -w vm.drop_caches = 3

关于O_DIRECT的话题暂时结束了,希望用户能更好的理解其对InnoDB内部的影响。后续我将继续关注O_DIRECT_NO_FSYNC对于其他文件系统的影响。

发表评论

坐等沙发
相关文章
MySQL 8.0 200W QPS!!!InnoDB大重构 #M1005#
MySQL 8.0 200W QPS!!!InnoDB大重构 …
滚蛋吧,MySQL主从复制延迟
滚蛋吧,MySQL主从复制延迟
MySQL 8.0.3性能大杀器 —— CATS
MySQL 8.0.3性能大杀器 —— CATS
2017年MySQL数据库技术嘉年华 —— 有态度的技术大会
2017年MySQL数据库技术嘉年华 —— 有态度…
IMG社区MySQL技术沙龙南京站圆满结束
IMG社区MySQL技术沙龙南京站圆满结束
改朝换代:MySQL Group Replication
改朝换代:MySQL Group Replication
myadmin 订阅者
我还没有学会写个人说明!

一触即发,2017年,数据库世界的诸神之战