mysql一直使用swap,致使swap空间用尽变卡

大体操做步骤:mysql

1.调整内核参数,/proc/sys/vm/swapiness算法

2.调整mysql参数,innodb_flush_methodsql

3.加mysql配置参数memlock,将mysql锁定在内存重防止被swapping out数据库

4.手动释放swap空间,swapoff /xx/xx  和swapon /xx/xxvim


====================================================api

避免将分配给MySQL的地址空间映射到swap上。对于频繁进行读写操做的系统而言,数据看似在内存而实际上在磁盘是很是糟糕的,响应时间的增加极可能直接拖垮整个系统。因此,做为运维人员,怎样作到尽可能避免MySQL惨遭Swap的毒手将显得尤其重要!缓存


SWAP是操做系统虚拟出来的一部份内存地址,它的物理存储元件是磁盘。在备份数据或恢复数据时,文件系统会向Linux系统请求大量的内存做为cache。在物理内存使用殆尽时候,为了确保程序运行,每每会将另外的一些占用物理内存地址空间的程序映射到swap分区上。bash

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

服务器产生Swa分区的缘由
1)copy一个大文件,好比上百G的backup包
2)正在mysqldump以及mysql import一个很大的库的时候。
3)大批量的并发操做的io writer和io read操做。并发

MySQL程序运行时,物理内存为MySQL分配了大量的物理地址空间,以提升执行的速率。为了不在执行消耗大量内存的操做时将MySQL所拥有的部分物理内存地址空间映射到swap分区上(好比出现了MySQL服务器Swap满了100%致使db很慢很卡的现象),可作一下调整(解决办法):
1)改系统内核参数/proc/sys/vm/swappiness。调整系统使用swap分区的倾向性,数值越低越倾向于释放文件系统的cache,不能避免Linux系统使用swap分区。swappiness=0表示最大限度使用物理内存,而后才是swap分区。swappiness=100表示积极使用swap分区,而且将内存上的数据及时的映射到swap分区上。

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

2)改MySQL参数innodb_flush_method,开启O_DIRECT模式。Innodb的buffer pool会直接绕过文件系统cache来访问磁盘,可是redo log依旧会使用文件系统cache。Redo Log是覆写模式的,即便使用了文件系统的cache也不会占用太多

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

4)指定MySQL使用大页内存(Large Page)。Linux上的大页内存是不会被换出物理内存的,和memlock有殊途同归之妙。

5)临时释放锁占据的swap。

=========================================================

在Mysql数据库维护中,会遇到的一个现象: MySQL内存持续增长,最高时物理内存消耗达到90%以上,致使swap使用率100%,进而形成内存不足,系统自动kill mysql进程。Mysql服务挂掉查看Mysql的error日志信息:
[ERROR] InnoDB: Unable to lock /usr/local/mysql/var/ibdata1, error: 11 
或者
InnoDB: mmap(137363456 bytes) failed; errno 12
2016-03-01 01:38:42 13064 [ERROR] InnoDB: Cannot allocate memory for the buffer pool
2016-03-01 01:38:42 13064 [ERROR] Plugin 'InnoDB' init function returned error.
2016-03-01 01:38:42 13064 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
2016-03-01 01:38:42 13064 [ERROR] Unknown/unsupported storage engine: InnoDB
2016-03-01 01:38:42 13064 [ERROR] Aborting

出现上面报错的缘由通常是系统内存资源不足形成的(error 11在mysql中是资源临时不可用),解决方法是升级系统内存或者添加swap;

1
2
3
4
5
6
7
8
9
10
MySQL的内存消耗分为:
1)会话级别的内存消耗:如sort_buffer_size等,每一个会话都会开辟一个sort_buffer_size来进行排序操做。
2)全局的内存消耗:例如:innodb_buffer_pool_size等,全局共享的内存段。
 
会话级的内存消耗多是一个缘由。关于会话级的内存消耗解释以下:
read_buffer_size, sort_buffer_size, read_rnd_buffer_size, tmp_table_size这些参数在须要的时候才分配,操做后释放。
这些会话级的内存,无论使用多少都分配该size的值,即便实际须要远远小于这些size。
每一个线程可能会不止一次须要分配buffer,例如子查询,每层都须要有本身的read_buffer,sort_buffer, tmp_table_size 等。
找到每次内存消耗峰值是不切实际的,所以建议能够用来衡量一下你实际修改一些变量值产生的反应,例如把 sort_buffer_size
从1MB增长到4MB而且在max_connections为1000 的状况下,内存消耗增加峰值并非你所计算的3000MB而是30MB。

首先在/etc/my.cnf的mysqld配置区域下增长下面一句(根据机器自己的内存配置来设置下面这个参数值):

1
2
3
4
[root@mysql01 ~] # vim /etc/my.cnf
[mysqld]
.......
innodb_buffer_pool_size = 128M

而后开启Swap分区,重启Mysql服务。

开启SWAP分区的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
1)建立用于交换分区的文件(block_size、number_of_block 大小能够根据机器自己配置状况进行自定义,)
[root@mysql01 ~] # dd if=/dev/zero of=/mnt/swap bs=1M count=4096
 
2)设置交换分区文件:
[root@mysql01 ~] # mkswap /mnt/swap
 
3)当即启用交换分区文件
[root@mysql01 ~] # swapon /mnt/swap
 
舒适提示:
若是在 /etc/rc . local 中有 "swapoff -a" ,则须要修改成 "swapon -a"
 
4)设置开机时自启用 SWAP 分区:
须要修改文件  /etc/fstab  中的 SWAP 行,添加:
[root@mysql01 ~] # vim /etc/fstab
/mnt/swap  swap swap defaults 0 0
 
5)修改swpapiness参数
在Linux系统中,能够经过查看 /proc/sys/vm/swappiness 内容的值来肯定系统对SWAP分区的使用原则。
当swappiness内容的值为0时,表示最大限度地使用物理内存,物理内存使用完毕后,才会使用SWAP分区。
当swappiness内容的值为100时,表示积极地使用SWAP分区,而且把内存中的数据及时地置换到SWAP分区。
 
查看修改前为0,须要在物理内存使用完毕后才会使用SWAP分区:
[root@mysql01 ~] # echo 0 > /proc/sys/vm/swappiness
 
能够上面的方法临时修改此参数,假设咱们配置为空闲内存少于10%时才使用SWAP分区,则操做方法以下:
[root@mysql01 ~] # echo 10 > /proc/sys/vm/swappiness
 
若须要永久修改此配置,在系统重启以后也生效的话,能够修改  /etc/sysctl .conf 文件,并增长如下内容: 
[root@mysql01 ~] # vim /etc/sysctl.conf
vm.swappiness=10
[root@mysql01 ~] # sysctl -p
 
6)最后重启mysql服务
[root@mysql01 ~] # /etc/init.d/mysqld restart

关闭SWAP分区的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
当系统出现内存不足时,开启 SWAP 可能会因频繁换页操做,致使 IO 性能降低。若是要关闭 SWAP,能够采用以下方法。
 
1) free  -m 查询 SWAP 分区设置:
[root@mysql01 ~] # free -m
 
2)使用命令 swapoff 关闭 SWAP,好比:
[root@mysql01 ~] # swapoff /mnt/swap
 
3)修改  /etc/fstab  文件,删除或注释相关配置,取消SWAP的自动挂载:
[root@mysql01 ~] # vim /etc/fsta
#/mnt/swap swap swap defaults 0 0
 
4)经过  free  -m  确认 SWAP 已经关闭。
[root@mysql01 ~] # free -m
 
5)swappiness 参数调整:
可使用下述方法临时修改此参数,这里配置为 0%:
[root@mysql01 ~] # echo 0 >/proc/sys/vm/swappiness
 
若须要永久修改此配置,在系统重启以后也生效的话,能够修改  /etc/sysctl .conf 文件,并增长如下内容:
[root@mysql01 ~] # vim /etc/sysctl.conf
vm.swappiness=0
[root@mysql01 ~] # sysctl -p

=========================================================
来看看曾经碰到的一个因为MySQL内存交换区引发的一场事故

 事故现象:公司的一个业务系统程序会调用大量的SQL,一天,发现MySQL的负载极其不稳定,尤为是Slave的负载有点猛,而后通过讨论准备再加一台Slave,。另加了一台Slave后,发现Slave的负载确实都回归正常了,本觉得息事宁人,可是过了两个小时后,新添加的Slave的负载暴增至100以上!原来的Slave服务则显示正常。大概过了两个小时,新增长的Slave的负载又回归正常了,可是又过了两个小时后,负责又飙升至100以上!因而乎,赶忙Troubleshooting!过程以下:

1)考虑到新增的server,由于内存,CPU等硬件的配置和原来数据库的server都不同(新增的Slave比原来的Slave的内存少了一半),必然配置参数的值也会不一样。因此就从MySQl的配置文件查起,如:sort_buffer_size的大小(由于考虑到有许多SQL包含排序),join_buffer_size(用于链接的缓存的大小),max_connections(最大链接数,但是经过show processlist;发现也没有超过设置的值),innodb_buffer_pool_size(确认是否为物理内存的合适比例)等等。

2)使用free -m查看内存时,发现SWAP既然使用了500MB!经过vmsata,发现si和so的值不断的变化,能够确定的是发生了内存交换。原来是SWAP捣的蛋!

内存交换区:当操做系统由于没有足够的内存而将一些虚拟内存写到磁盘就会发生内存交换。

内存交换对MySQL性能影响是极其糟糕的。它破坏了缓存在内存的目的,而且相对于使用很小的内存作缓存,使用交换区的性能更差。MySQL和存储引擎有不少算法来区别对待内存中的数据和硬盘上的数据,由于通常都是假设内存数据访问代价更低。

由于内存交换对用户进程不可见,MySQL(或存储引擎)并不知道数据实际上已经移动到磁盘,还会觉得仍然在内存中呢。

结果会致使不好的性能。例如。若存储引擎认为数据依然在内存,可能以为为"短暂"的内存操做锁定一个全局互斥变量(例如,InnoDB缓冲池Mutex)是OK的。若是这个操做实际上引发了硬盘I/O,直到I/O操做完成前任何操做都会被挂起。这意味着内存交换比直接作硬盘I/O操做还要糟糕。

在Linux上,能够用vmstat来监控内存交换。最好查看si和so列报告的内存交换I/O活动,这比看swapd列报告的交换区利用率更重要。咱们都喜欢si和so列的值为0,而且必定要保证它们低于每秒10块。

能够经过正确地配置MySQL缓冲来解决大部份内存交换问题,可是有时操做系统的虚拟内存系统仍是会决定交换MySQL内存。这一般发生在操做系统看到MySQL发出了大量I/O,所以尝试增长文件缓存来保存更多数据时。若是没有足够的内存,有些东西就必须交换出去,有些可能就是MySQL自己。

有些人主张彻底禁用交换文件。这样作是很危险的,由于禁用内存交换就至关于给虚拟内存设置了一个不可动摇的限制。若是MySQL须要临时使用很大一块内存,或者有很耗内存的进程运行在同一台server上(如夜间的批量任务),MySQL可能会内存溢出,崩溃,或者被操做系统kill掉。

操做系统一般容许对虚拟内存和I/O进行一些控制。最基本的方法就是修改/proc/sys/vm/swappiness为一个很小的值,如0或1。这等同于告诉内核除非虚拟内存彻底满了,不然不要使用交换区。下面是如何检查这个值的例子:

1
2
cat  /proc/sys/vm/swappiness
60

这个值显示为60,这是默认的设置(范围是0~100)。对于服务器而言这是个很糟糕的默认值。服务器应该设置为0:

1
echo  0 >  /proc/sys/vm/swappiness

另外一个选项是修改存储引擎怎么读取和写入数据。使用innodb_flush_method=O_DIRECT,减轻I/O压力。DIRECT I/O并不缓存,所以操做系统并不能把MySQL视为增长文件缓存的缘由。这个参数只对InnoDB有效。你也可使用大页,不参与换入换出,这对MyISAM和InnoDB都有效。

另外一个选择是使用MySQL的memlock配置项,能够把MySQL锁定在内存。这能够避免交换,可是也可能带来危险:若是没有足够的可锁定内存,MySQL在尝试分配更多内存时就会崩溃。

解决问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
第一种方法:修改系统对虚拟内存的控制
[root@mysql01 ~] # echo 0 > /proc/sys/vm/swappiness
 
#要想永久生效,将其配置写入/etc/sysctl.conf文件中
[root@mysql01 ~] # echo "vm.swappiness=0" >> /etc/sysctl.conf
#令其当即生效
[root@mysql01 ~] # sysctl -p
 
第二种方法:修改innodb_flush_method参数
#注意innodb_flush_method是个全局变量,而且不支持动态修改,因此修改配置文件,重启MySQL
[root@mysql01 ~] # vim /etc/my.cnf
innodb_flush_method=O_DIRECT
 
#添加其参数的配置,若是线上正在运行的数据库,就要先:
mysql> stop slave;
 
#而后重启MySQL
[root@mysql01 ~] # /etc/init.d/mysqld restart

对于修改memlock配置项,不推荐。

结果:新增长的slave负载正常。swap的使用也降到了10MB的样子。

相关文章
相关标签/搜索