在 MySQL 数据库中,几乎默认会将 InnoDB 的磁盘刷新参数 innodb_flush_method 设置为 O_DIRECT ,以此提升数据库的刷新性能。
Oracle 数据库也有提供了参数 FILESYTEMIO_OPTIONS 可将刷新设置为 O_DIRECT。
然而,PostgreSQL 数据库并不支持 O_DIRECT,所以 PG 存在数据库性能抖动的问题,无法在海量互联网业务中使用。
然而,什么是 O_DIRECT 呢?
O_DIRECT 内存地址对齐
相信很多同学会说,O_DIRECT 是指文件读写时,数据直接访问磁盘,而不要经过操作系统的缓存。
嗯,这个没有错,但 show me your code 。
接着,Java 开发工程师、DBA 们就一脸茫然了。
估计你让一个 P8 工程师来,也写不出。
不信?那你问问身边的工程师们。
O_DIRECT 原理本身不特别复杂,一看即懂,一句话就能说清。
但这个特性却非常小众,按我的理解只存在于类似数据库的开发领域。
绝大部分业务的开发工程师们,与文件打交道就是打印日志。
日志打印主要目的是性能,不需要 O_DIRECT ,数据若发生丢失,丢就丢了吧。
甚至,Java 语言本身都没提供 O_DIRECT 的文件选项。若想使用,还需要自己额外进行一层底层的封装。
好吧,接着让姜老师写个最简单的 demo :
这个 demo 就是向文件 f.test 写入16384个字节。
可以看到,这里 open 的时候加入了额外的 O_DIRECT 选项,接着通过 pwrite 函数将数据写入文件。
但这里需要特别注意的是 O_DIRECT 写入,要求内存地址与扇区大小对齐。下面是官方文档的说明:
The O_DIRECT flag may impose alignment restrictions on the length and address of user-space buffers and the file offset of I/Os.
因此,你会看到下面这两行用于处理内存对齐的逻辑:
buf = (char*)malloc(sizeof(char*)*PAGE_SIZE*2);
buf_aligned = (char*)ut_align(buf,SECTOR_SIZE); // align address for DIRECT_IO
只有做了地址对齐,才能使用 O_DIRECT,否则 pwrite 后的 assert 校验就会失败。
但扇区大小是多少呢?文档的说法就相当玄幻了:
In Linux alignment restrictions vary by filesystem and kernel version and might be absent entirely. However there is currently no filesystem-independent interface for an application to discover these restrictions for a given file or filesystem.
文档的意思大致就是扇区大小是可变化的,而且也没有提供一个统一的接口去获取文件系统的扇区大小。
根据经验,我们知道大部分磁盘的扇区大小是 512 字节,SSD 的扇区大小是 4K。
因此,若要使用 O_DIRECT ,建议直接按 4K 对齐,这样就无需关注下面的具体存储类型了(至少目前好像还没有扇区大小超过 4K 的设备)。
细心的同学会发现,在上面的代码中,使用 O_DIRECT 后,还需要进行 fsync 这又是为什么呢?
O_DIRECT 到底还要不要 fsync ?
是的,使用 O_DIRECT 选项后,文件写入时会绕过操作系统缓存,数据直接落盘:
从上图可以看到使用 O_DIRECT 选项后,磁盘读写从文件系统层直接访问最底层的存储设备,不走操作系统层的 Page Cache。
但即便使用 O_DIRECT ,在写入后,还是需要通过调用一次 fsync 用于保证数据真正落到磁盘。
这是因为文件对应的元数据信息还没有落盘,例如文件的大小,最后的修改时间等。
但是,若文件没有增长呢?只是更新了一个页的数据。
是的,那这时就无需在写入文件后,再进行 fsync 操作,从而进一步提升系统性能。
MySQL 5.7.25 版本开始,就进行了类似这样的优化,对参数 innodb_flush_method 提供了新的选项 O_DIRECT_NO_FSYNC 。看文档的说明:
O_DIRECT_NO_FSYNC: InnoDB uses O_DIRECT during flushing I/O, but skips the fsync() system call after each write operation.
Prior to MySQL 5.7.25, 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 5.7.25, 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.
总结
今天姜老师深入讲解了 O_DIRECT 的使用,这是一个文件系统操作非常底层的使用选项,一般仅用于数据库中。
今天留下2道思考题,相信答对者年薪百万那是妥妥的:
MySQL InnoDB存储引擎刷新磁盘使用 O_DIRECT,他是根据多少大小进行字节对齐的呢?
为什么重做日志文件写入却不需要启用 O_DIRECT 选项呢?
RAW格式是否还有性能优势呢?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.