MySQL如何避免使用Linux的swap分区而提高读写性能


MySQL如何避免使用Linux的swap分区而提高读写性能


Linux有不少很好的内存、IO调度机制,可是并不会适用于全部场景。对于DBA来讲Linux比较让人头疼的一个地方是,它不会由于MySQL很重要就避免将分配给MySQL的地址空间映射到swap上。对于频繁进行读写操做的系统而言,数据看似在内存而实际上在磁盘是很是糟糕的,响应时间的增加极可能直接拖垮整个系统。这篇blog主要讲讲咱们做为DBA,怎样尽可能避免MySQL惨遭swap的毒手。html

首先咱们要了解点基础的东西,好比说为何会产生swap。假设咱们的物理内存是16G,swap是4G。若是MySQL自己已经占用了12G物理 内存,而同时其余程序或者系统模块又须要6G内存,这时候操做系统就可能把MySQL所拥有的一部分地址空间映射到swap上去。mysql

cp一个大文件,或用mysqldump导出一个很大的数据库的时候,文件系统每每会向Linux申请大量的内存做为cache,一不当心就会致使L使用swap。这个情景比较常见,如下是最简单的三个调整方法:linux

一、/proc/sys/vm/swappiness的内容改为0(临时),/etc/sysctl.conf上添加vm.swappiness=0(永久)
这个参数决定了Linux是倾向于使用swap,仍是倾向于释放文件系统cache。在内存紧张的状况下,数值越低越倾向于释放文件系统cache。
固然,这个参数只能减小使用swap的几率,并不能避免Linux使用swap。sql

二、修改MySQL的配置参数innodb_flush_method,开启O_DIRECT模式。
这种状况下,InnoDB的buffer pool会直接绕过文件系统cache来访问磁盘,可是redo log依旧会使用文件系统cache。值得注意的是,Redo log是覆写模式的,即便使用了文件系统的cache,也不会占用太多。数据库

三、添加MySQL的配置参数memlock
这个参数会强迫mysqld进程的地址空间一直被锁定在物理内存上,对于os来讲是很是霸道的一个要求。必需要用root账号来启动MySQL才能生效。

还有一个比较复杂的方法,指定MySQL使用大页内存(Large Page)。Linux上的大页内存是不会被换出物理内存的,和memlock有殊途同归之妙。具体的配置方法能够参 考:http://harrison-fisk.blogspot.com/2009/01/enabling-innodb-large-pages- on-linux.htmlapi

以前介绍了MySQL如何避免使用swap的四个方法。这里须要补充一下原理和实现机制,对于Linux api不感兴趣的同窗能够直接跳过。缓存

1、操做系统设置swap的目的
程序运行的一个必要条件就是足够的内存,而内存每每是系统里面比较紧张的一种资源。为了知足更多程序的要求,操做系统虚拟了一部份内存地址,并将之映射到 swap上。对于程序来讲,它只知道操做系统给本身分配了内存地址,但并不清楚这些内存地址到底映射到物理内存仍是swap。
物理内存和swap在功能上是同样的,只是由于物理存储元件的不一样(内存和磁盘),性能上有很大的差异。操做系统会根据程序使用内存的特色进行换入和换 出,尽量地把物理内存留给最须要它的程序。可是这种调度是按照预先设定的某种规则的,并不能彻底符合程序的须要。一些特殊的程序(好比MySQL)但愿 本身的数据永远寄存在物理内存里,以便提供更高的性能。因而操做系统就设置了几个api,以便为调用者提供“特殊服务”。oracle

2、Linux提供的几个api
一、mlockall()和munlockall()
这一对函数,可让调用者的地址空间常驻物理内存,也能够在须要的时候将此特权取消。mlockall()的flag位能够是MCL_CURRENT和 MCL_FUTURE的任意组合,分别表明了“保持已分配的地址空间常驻物理内存”和“保持将来分配的地址空间常驻物理内存”。对于Linux来讲,这对 函数是很是霸道的,只有root用户才有权限调用。app

二、shmget()和shmat()
这一对函数,能够向操做系统申请使用大页内存(Large Page)。大页内存的特色是预分配和永驻物理内存,由于使用了共享内存段的方式,page table有可能会比传统的小页分配方式更小。对于多进程共享内存的程序(好比ORACLE),大页内存可以节省不少page table开销;而对于MySQL来讲,性能和资源开销都没有显著变化,好处就在于减小了内存地址被映射到swap上的可能。至于为何是减小,而不是彻底避免,以后再讲解。函数

三、O_DIRECT和posix_memalign()
以上两个方法都不会减小内存的使用量,调用者的本意是获取更高的系统特权,而不是节约系统资源。O_DIRECT是一种更加理想化的方式,经过避免 double buffer,节省了文件系统cache的开销,最终减小swap的使用率。O_DIRECT是Linux IO调度相关的标志,在open函数里面调用。经过O_DIRECT标志打开的文件,读写都不会用到文件系统的cache。传统的数据库(ORACLE、MySQL)基本都有O_DIRECT相关的开关,在提升性能的同时,也减小了内存的使用。至于posix_memalign(),是用来申请对齐的内存地址的。只有用posix_memalign()申请的内存地址,才能用来读写O_DIRECT模式下的文件描述符。

四、madvise()和fadvise()
这对函数也是比较温和的,能够将调用者对数据访问模式的预期传递给Linux,以期获得更好的性能。
咱们比较感兴趣的是MADV_DONTNEED和FADV_NOREUSE这两个flag。前者会建议Linux释放指定的内存区域,然后者会建议文件系统释放指定文件所占用的cache。

3、MySQL内存使用相关的一些代码
一、memlock
在MySQL的源码目录里面查询memlock,能够知道这个参数的做用是使MySQL调用mlockall()。在源码里面匹配能够得知NDB、MyISAM和 mysqld都调用了mlockall()。NDB是能够独立于MySQL而存在的存储引擎,此处按下不表。mysqld调用mlockall()的方式 有点出乎意料,在init_server_components()函数里传给mlockall()的flag是MCL_CURRENT,也就是说以后申 请的内存一律不用锁住。再看看MyISAM的调用顺序是:mlockall() <- lock_memory() <- mi_repair(),MyISAM只有修复的时候会调用mlockall()函数。

二、large-pages
根据Linux的内核文档,大页内存有两种方法能够用到:一种是建立hugetlb类型的文件,并将它mmap到程序的内存地址里面,而后进行正常的读写 操做。另一种是以前说到的shmget()+shmat(),也正是MySQL采用的方式。在MySQL的源码目录里面匹配shmget,能够发现 BDB、NDB、InnoDB、MyISAM都调用了这个函数。接着看一下比较经常使用的InnoDB和MyISAM引擎。
在InnoDB里面能够找到os_mem_alloc_large()调用了shmget(),而调用os_mem_alloc_large()的函数只 有buf_pool_init()——InnoDB Buffer Pool的初始化函数。根据观察获得的结论是,InnoDB会根据配置参数在Buffer Pool里面使用大页内存,Redo log貌似就没有这个待遇了。
对于MyISAM,在storage层级的代码里面找不到对shmget()的直接调用。这是由于MyISAM是MySQL的原生存储引擎,不少函数存放 在上一层的mysys目录里面。经过搜索shmget(),咱们能够找到MyISAM的调用顺序是这样的:shmget() <- my_large_malloc_int() <- my_large_malloc() <- init_key_cache()。也就是说MyISAM只有索引缓存用到了大页内存,这是很容易理解,由于MyISAM的数据是直接扔给文件系统作缓存 的,无法使用大页内存。

三、innodb_flush_method
O_DIRECT是BDB、NDB、InnoDB特有的参数,在这里只讨论InnoDB这个比较常见的引擎。在InnoDB的源码目录里面匹配 O_DIRECT,很容易找到一个叫作os_file_set_nocache()的函数,而这个函数做用是将文件的打开方式改成O_DIRECT模式。 再跟踪一下,会发现只有os_file_create()函数调用了os_file_set_nocache()。虽然函数名里面还有create,实际 上os_file_create()会根据传入参数的不一样,选择打开或者新建一个文件。同时os_file_create()还会根据MySQL的配置, 来调用os_file_set_nocache()关闭文件系统的相应cache。在os_file_create()函数里面有以下一段代码:
/* We disable OS caching (O_DIRECT) only on data files */
if (type != OS_LOG_FILE &&
srv_unix_file_flush_method == SRV_UNIX_O_DIRECT)
{
os_file_set_nocache(file, name, mode_str);
}
这段代码的意思是,只有InnoDB的数据文件有资格使用O_DIRECT模式,Redo log是不能使用的。

以上的分析基于5.0.85版本的原版MySQL,InnoDB是Innobase。
版本不一样状况下可能会有一些出入,欢迎参与讨论。

参考文献:
Virtual memory@wiki
All about Linux swap space
HugeTLB – Large Page Support in the Linux Kernel
Page table@wiki

来源:http://www.taobaodba.com/html/552_mysql_avoid_swap.html

http://www.taobaodba.com/html/554_mysql_avoid_swap_2.html

永久连接 : http://www.ha97.com/4201.html

相关文章
相关标签/搜索