MySQL根据5.1.34之前版本的一个BUG分析O_DIRECT

时间:2022-05-03
本文章向大家介绍MySQL根据5.1.34之前版本的一个BUG分析O_DIRECT,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Mysql错误日志:

Version:  '5.1.34-percona-highperf-log'  socket:  '/home/mysql/mysql.sock'  port:  3306  Source distribution
140324  5:00:02  InnoDB: Failed to set O_DIRECT on file  /tmp/#sql593e_191_0.ibd: CREATE: Invalid argument, continuing anyway
140324  5:00:02  InnoDB: O_DIRECT is known to result in  'Invalid argument' on Linux on tmpfs, see MySQL Bug#26662
140324  5:00:02  InnoDB: Failed to set O_DIRECT on file  /tmp/#sql593e_191_0.ibd: OPEN: Invalid argument, continuing anyway
140324  5:00:02  InnoDB: O_DIRECT is known to result in  'Invalid argument' on Linux on tmpfs, see MySQL Bug#26662
140324  5:00:02  InnoDB: Failed to set O_DIRECT on file  /tmp/#sql593e_192_0.ibd: CREATE: Invalid argument, continuing anyway
140324  5:00:02  InnoDB: O_DIRECT is known to result in  'Invalid argument' on Linux on tmpfs, see MySQL Bug#26662
140324  5:00:02  InnoDB: Failed to set O_DIRECT on file  /tmp/#sql593e_192_0.ibd: OPEN: Invalid argument, continuing anyway
140324  5:00:02  InnoDB: O_DIRECT is known to result in  'Invalid argument' on Linux on tmpfs, see MySQL Bug#26662

innodb_flush_method 这个参数控制着innodb数据文件及redo log的打开、刷写模式。对于这个参数,文档上是这样描述的:

从MySQL 5.6的版本开始,也就是InnoDB 1.2版本中(PS:MariaDB 10.x版本将集成InnoDB 1.2版本),对于参数innodb_flush_method提供了一个新的设置值O_DIRECT_NO_FSYNC。

有四个值:fdatasync,O_DSYNC,O_DIRECT,O_DIRECT_NO_FSYNC

  • 默认是fdatasync,调用fsync()去刷数据文件与redo log的buffer
  • 为O_DSYNC时,innodb会使用O_SYNC方式打开和刷写redo log,使用fsync()刷写数据文件
  • 为O_DIRECT时,innodb使用O_DIRECT打开数据文件,使用fsync()刷写数据文件跟redo log
  • 为O_DIRECT_NO_FSYNC时,InnoDB存储引擎将依然使用O_DIRECT选项打开数据表空间文件,但是在刷新时,不再需要需要额外的fsync操作

首先文件的写操作包括三步:open,write,flush

  • 上面最常提到的fsync(int fd)函数,该函数作用是flush时将与fd文件描述符所指文件有关的buffer刷写到磁盘,并且flush完元数据信息(比如修改日期、创建日期等)才算flush成功。
  • 使用O_SYNC方式打开redo文件表示当write日志时,数据都write到磁盘,并且元数据也需要更新,才返回成功
  • O_DIRECT则表示我们的write操作是从mysql innodb buffer里直接向磁盘上写

至此总结一下三者写数据方式:

  • fdatasync模式:写数据时,write这一步并不需要真正写到磁盘才算完成(可能写入到操作系统buffer中就会返回完成),真正完成是flush操作,buffer交给操作系统去flush,并且文件的元数据信息也都需要更新到磁盘。
  • O_DSYNC模式:写日志操作是在write这步完成,而数据文件的写入是在flush这步通过fsync完成
  • O_DIRECT模式:数据文件的写入操作是直接从mysql innodb buffer到磁盘的,并不用通过操作系统的缓冲,而真正的完成也是在flush这步,日志还是要经过OS缓冲

优点:

  1. 目前都是硬盘如SSD、F/M卡 IO已经很快了,无需再利用系统缓存。
  2. 最为安全和稳妥的做法还是将参数innodb_flush_method设置为O_DIRECT。
  3. 若重做日志使用O_DIRECT,写入重做日志文件的过程会变慢(因为不是仅写入到操作系统缓存),Group Commit的效率就会变差。