mysql存储内存中(tmpfs)的问题

MySQL的相关参数:
default-storage-engine = INNODB
innodb_flush_method=O_DIRECT
tmpdir = /tmp/mysqltmp
/tmp/mysqltmp目录为tmpfs

php

发现error日志中出现html

131119 15:12:55 InnoDB: Failed to set O_DIRECT on file ./BetBrainV4/Participant.ibd: OPEN: Invalid argument, continuing anywaymysql

131119 15:12:55 InnoDB: O_DIRECT is known to result in 'Invalid argument' on Linux on tmpfs, see MySQL Bug#26662linux


解决方式:
sql

1.建立memory或myisam的临时表代替innodb;
2.修改innodb_flush_method为非O_DIRECT,如O_DSYNC、fdatasync;
参考:

http://bugs.mysql.com/bug.php?id=26662
http://bugs.mysql.com/bug.php?id=45671数据库


下面介绍一个解决方式的思路:编程

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

有三个值:fdatasync(默认),O_DSYNC,O_DIRECT安全

默认是fdatasync,调用fsync()去刷数据文件与redo log的bufferasync

为O_DSYNC时,innodb会使用O_SYNC方式打开和刷写redo log,使用fsync()刷写数据文件

为O_DIRECT时,innodb使用O_DIRECT打开数据文件,使用fsync()刷写数据文件跟redo log

首先文件的写操做包括三步: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缓冲


2个思考

一、innodb_flush_method究竟应不该该使用O_DIRECT?

全部MySQL调优的建议都说,若是硬件没有预读功能,那么使用O_DIRECT将极大下降InnoDB的性能,由于O_DIRECT跳过了操做系统的文件系统Disk Cache,让MySQL直接读写磁盘了。

可是在个人实践中来看,若是不使用O_DIRECT,操做系统被迫开辟大量的Disk Cache用于innodb的读写缓存,不但没有提升读写性能,反而形成读写性能急剧降低。并且buffer pool的数据缓存和操做系统Disk Cache缓存形成了Double buffer的浪费,显然从我这个实践来看,浪费得很是厉害。

说O_DIRECT形成MySQL直接读写磁盘形成得性能降低问题,我以为彻底是杞人忧天。由于从JavaEye的数据库监测来看,Innodb的buffer pool命中率很是高,有98%以上,真正的磁盘操做是微乎其微的。为了1%的磁盘操做可以获得Disk Cache,而浪费了98%的double buffer内存空间,不管从性能上看,仍是从内存资源的消耗来看,都是很是不明智的。

二、innodb_log_file_size究竟应该大一点,仍是小一点?

全部MySQL调优建议都说,innodb_log_file_size要越大越好,避免无谓的buffer pool的flush操做。

可是在个人实践中来看,innodb_log_file_size开得太大,会明显增长innodb的log写入操做,并且会形成操做系统须要更多的Disk Cache开销。
innodb_flush_method=O_DIRECT是必须的,而innodb_log_file_size也不宜太大。


下面是一段摘录的备忘


http://www.orczhou.com/index.php/2009/08/innodb_flush_method-file-io/

innodb_flush_log_at_trx_commit参数肯定日志文件什么时候write、flush。innodb_flush_method则肯定日志及数据文件如何write、flush。在Linux下,innodb_flush_method能够取以下值:fdatasync, O_DSYNC, O_DIRECT,那这三个值分别是如何影响文件写入的?首先咱们须要先来了解Linux的文件I/O是如何工做的。

先来看看Linux/Unix文件I/O的一个典型例子:(Linux 2.6.24测试,gcc编译)

/**
	A test about syscall of File I/O
	Author:supu@TaobaoDBA
	supu@taobao.com http://orczhou.com http://www.taobaodba.com
*/

#include   "stdlib.h"           /* for exit */
#include   "unistd.h"           /* for write fdatasync*/
#include    "fcntl.h"           /* for open  */
int main(void){
	int fd;
	if((fd=open("/home/zzx/test.file",O_WRONLY|O_APPEND|O_DSYNC))<0){
		exit(1);
        }
        char buff[]="abcdef";
        if(write(fd,buff,6)!= 6){
                exit(2);
        }
        if(fdatasync(fd)==-1){
                exit(3);
        }
        exit(0);
}

程序描述了通常的文件I/O操做的三个过程open、write、fdatasync,分别是打开文件、写文件、flush操做(将文件缓存刷到磁盘上)。

1、Open阶段

open("test.file",O_WRONLY|O_APPDENT|O_SYNC))

系统调用Open会为该进程一个文件描述符fd【附录2】。这里使用了O_WRONLY|O_APPDENT|O_SYNC打开文件:

  1. O_WRONLY表示咱们以"写"的方式打开,告诉内核咱们须要向文件中写入数据;

  2. O_APPDENT告诉内核以"追加"的方式写文件;

  3. O_DSYNC告诉内核,当向文件写入数据的时候,只有当数据写到了磁盘时,写入操做才算完成(write才返回成功)。和O_DSYNC同类的文件标志,还有O_SYNC,O_RSYNC,O_DIRECT。

    • O_SYNC比O_DSYNC更严格,不只要求数据已经写到了磁盘,并且对应的数据文件的属性(例如文件长度等)也须要更新完成才算write操做成功。可见O_SYNC较之O_DSYNC要多作一些操做。

    • O_RSYNC表示文件读取时,该文件的OS cache必须已经所有flush到磁盘了【附录3】

    • 若是使用O_DIRECT打开文件,则读/写操做都会跳过OS cache,直接在device(disk)上读/写。由于没有了OS cache,因此会O_DIRECT下降文件的顺序读写的效率。


2、Write阶段

write(fd,buf,6)

在使用open打开文件得到文件描述符以后,咱们就能够调用write函数来写入数据了,write会根据前面的open参数不一样,而表现不一样。

3、Flush阶段

fdatasync(fd) == -1

write操做后,咱们还调用了fdatasync来确保文件数据flush到了disk上。fdatasync返回成功后,那么能够认为数据已经写到了磁盘上。像这样的flush的函数还有fsync、sync。

  1. Fsync和fdatasync的区别等同于O_SYNC和O_DSYNC的区别。

  2. Sync函数表示将文件在OS cache中的数据排入写队列,并不确认是否真的写磁盘了,因此sync并不能够靠。

忽略文件打开的过程,一般咱们会说“写文件”有两个阶段,一个是调用write咱们称为写数据阶段(实际上是受open的参数影响),调用fsync(或者fdatasync)咱们称为flush阶段。

回到MySQL,参数Innodb_flush_method(Linux)能够设定为:Fdatasync、O_DSYNC、O_DIRECT。咱们看看这个三个参数是如何影响程序MySQL对日志和数据文件的操做:


Open log Flush log Open datafile Flush data
Fdatasync
fsync()
fsync()
O_DSYNC O_SYNC

fsync()
O_DIRECT
fsync() O_DIRECT Fsync()

fdatasync被认为是安全的,由于在MySQL总会调用fsync来flush数据。使用O_DSYNC是有些风险的,有些OS会忽略该参数O_SYNC

咱们看到O_DIRECT和fdatasync和很相似,可是它会使用O_DIRECT来打开数据文件。有数据代表,若是是大量随机写入操做,O_DIRECT会提高效率。可是顺序写入和读取效率都会下降。因此使用O_DIRECT须要谨慎。

参考文章:

  1. Unix环境高级编程(第二版)

  2. http://rdc.taobao.com/blog/dba/html/296_innodb_flush_method_performance.html

  3. http://dev.mysql.com/doc/refman/5.0/en/innodb-parameters.html

  4. http://www.ukuug.org/events/linux2001/papers/html/AArcangeli-o_direct.html

  5. http://xiaomeng.yo2.cn/articles/buffered-io-and-non-buffered-io.html

  6. http://articles.directorym.net/Operating_Systems_System_Calls_and_IO-a894576.html

  7. http://www.ibm.com/developerworks/cn/linux/l-cn-read/

  8. http://www.kernel.org/doc/man-pages/online/pages/man2/open.2.html

  9. 系统调用:http://www.ibm.com/developerworks/cn/linux/kernel/syscall/part1/index.html

【附录1】文章须要你了解什么是“系统调用“,参考:

http://www.ibm.com/developerworks/cn/linux/kernel/syscall/part1/index.html

能够简单的理解为:“系统调用“是在内核之上的一层封装。由内核直接提供接口,“系统调用”须要陷入内核执行(内核态)。其中fdatasync就是一个系统调用,该系统调用能够通知OS马上将OS Cache中的数据Flush到磁盘文件中。

【附录2】这时候内核会为该该进程打开的文件分配一个文件描述符,并将该文件描述符返回给该进程。在内核的文件表中新建一个文件项,标记文件状态、文件当前偏移、以及I节点(v节点)的位置,内核还会打开该文件的I节点(这里记录文件的操做的函数指针,例如读操做、写操做)。

【附录3】O_RSYNC个人理解是,对于同一个文件描述符能够保证读数据安全。同一个文件描述符包括dup和fcntl函数dup的文件描述符,即共用同一个文件表项。O_RSYNC不是咱们今天关注的,暂时忽略

未解问题:

  1. O_DIRECT在哪些OS(或者FS)上可以正常工做?

  2. O_SYNC在哪写OS上不能正常工做呢?

  3. 内核的read、write是FS级别的仍是内核(kernel)级别?

  4. 文章innodb_flush_method带来的性能影响中O_DSYNC、和fdatasync效率差不少,这是为何?

(全文完)

相关文章
相关标签/搜索