针对 MySQL 的 Linux 优化

1.OS文件系统的选择

使用Linux系统时,应选用 ext4 或 xfs 文件系统,业界资深人士推荐 xfs。查看文件系统方法如下:

[root@MySQL-01 ~]# df -lhT
Filesystem           Type   Size  Used Avail Use% Mounted on
/dev/sda2            ext4    62G  2.2G   57G   4% /
tmpfs                tmpfs   32G     0   32G   0% /dev/shm
/dev/sda1            ext3    97M   26M   67M  28% /boot
/dev/sda5            ext4    33G  176M   32G   1% /home
/dev/mapper/db-mysql xfs    3.0T   18G  3.0T   1% /mysql

 

2.禁止操作系统更新文件的atime属性

atime是Linux/UNIX系统下的一个文件属性,每当读取文件时,操作系统都会将读操作时间回写到磁盘上。对于读写频繁的数据库文件来说,记录文件的访问时间一般没有任何用处,却会增加磁盘系统的负担,影响I/O性能!因此,可以通过设置文件系统的mount熟悉,阻止操作系统写atime信息,减轻磁盘I/O负担。方法如下:

(1)修改文件系统配置文件/etc/fstab,指定 noatime 选项:

UUID=33958004-e8a7-4135-844f-707a5537e86a /data                   ext4  noatime     0    1

(2)对于 xfs 文件系统,对于能够在断电或发生其它主机故障时保护缓存中数据的设备,应该以 nobarrier 选项挂载文件系统:

/dev/db/mysql           /mysql                  xfs     defaults,noatime,nobarrier   0     0

(3)重新mount文件系统使其修改生效:

[root@MySQL-01 ~]# mount -o remount /mysql

 

3.调整I/O调度算法

(1)查看当前系统支持的I/O调度算法:

[root@MySQL-01 ~]# dmesg | grep -i scheduler
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered (default)
[root@MySQL-01 ~]# 

(2)查看当前设备(/dev/sda)使用的I/O调度算法:

[root@MySQL-01 ~]# cat /sys/block/sda/queue/scheduler     
noop anticipatory deadline [cfq] 
[root@MySQL-01 ~]# 

(3)修改当前设备使用的I/O调度算法,普通磁盘可以选择Deadline,SSD我们可以选择使用NOOP或者Deadline

[root@MySQL-01 ~]# echo "deadline" >> /sys/block/sda/queue/scheduler 
[root@MySQL-01 ~]# cat /sys/block/sda/queue/scheduler                
noop anticipatory [deadline] cfq 
[root@MySQL-01 ~]# 

 永久修改I/O调度算法,可以通过修改内核引导参数,增加elevator=调度算法名

[root@MySQL-01 ~]# vim /boot/grub/menu.lst 

更改后的内容:

[root@MySQL-01 ~]# grep "deadline" /boot/grub/menu.lst      
        kernel /vmlinuz-2.6.32-220.el6.x86_64 ro root=UUID=c0618639-a967-4601-bca7-cc3b99c5c332 elevator=deadline rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD quiet SYSFONT=latarcyrheb-sun16 rhgb crashkernel=auto  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM
[root@MySQL-01 ~]# 

 

4.NUMA架构优化

从系统架构来看,目前的商用服务器大体可以分为三类:

(1)对称多处理器架构(Symmetric Multi-Processor,SMP)

(2)非一致存储访问架构(Non-Uniform Memory Access,NUMA)

(3)海量并行处理架构(Massive Parallel Processing,MPP)

一般服务器是SMP或者NUMA架构的较多。这里只对NUMA架构进行说明。

NUMA把一台计算机分成多个节点(Node),每个节点内部拥有多个CPU,节点内部使用共有的内存控制器,节点之间是通过互联模块进行连接和信息交互,因此节点的所有内存对于本节点所有的CPU是等同的,而对于其他节点中的所有CPU都是不同的。因此每个CPU可以访问整个系统内存,但是访问本地节点的内存速度最快(不需要经过互联模块),访问非本地节点的内存速度较慢(需要经过互联模块),即CPU访问内存的速度与节点的距离有关,距离称为Node Distance。

显示当前NUMA的节点情况:

[root@localhost ~]# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6
node 0 size: 16338 MB
node 0 free: 136 MB
node 1 cpus: 1 3 5 7
node 1 size: 16384 MB
node 1 free: 66 MB
node distances:
node   0   1 
  0:  10  20 
  1:  20  10 
[root@localhost ~]# free -m
             total       used       free     shared    buffers     cached
Mem:         32060      31856        204          0        362      13016
-/+ buffers/cache:      18477      13582
Swap:         7999          6       7993
[root@localhost ~]# 

当前服务器上有两个节点Node 0和Node 1,Node 0的本地内存约为16GB,Node 1的本地内存约为16GB,可以看出系统一共有32GB内存

节点之间的距离(Node Distance)是指节点1访问节点0上的内存需要付出的代价的一种表现形式。在上述例子中,Linux节点本地内存声明距离为10,非本地内存声明距离20.

NUMA的内存分配策略分为以下4种:

(1)缺省default:总是在本地节点分配(分配在当前进程运行的节点上)

(2)绑定bind:强制分配到指定节点上

(3)交叉interleave:在所有节点或者指定节点上交叉分配内存

(4)优先preferred:在指定节点上分配,失败则在其他节点分配

显示当前系统NUMA策略:

[root@localhost ~]# numactl --show
policy: default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7 
cpubind: 0 1 
nodebind: 0 1 
membind: 0 1 
[root@localhost ~]# 

因为NUMA默认的内存分配策略是优先在进程所在CPU的本地内存中分配,会导致CPU节点之间内存分配不均衡,当某个CPU节点内存不足时,会导致SWAP发生,而不是从远程节点分配内存,这就是Swap Insanity现象。

MySQL是单进程多线程架构的数据库,当NUMA采用默认的内存分配策略时,MySQL进程会被并且仅仅会被分配到NUMA的一个节点上去。假设MySQL进程被分配到Node 1运行,这个节点的本地内存是8GB,而MySQL配置了14GB内存,MySQL分配的14GB内存中,超过节点本地内存部分(14GB-8GB=6GB)Linux系统宁愿使用Swap也不会使用其他节点的物理内存。在这种情况下,能观察到系统虽然总共可用的物理内存还很多,但是MySQL进程已经开始使用Swap了。

MySQL对NUMA的特性支持不好,如果单机只运行一个MySQL实例,可以选择关闭NUMA,关闭的方式有两种:

(1)硬件层,在BIOS中设置关闭

(2)OS内核层,启动时设置numa=off

修改/etc/grub.conf,添加numa=off

[root@MySQL-01 ~]# vim /etc/grub.conf
[root@MySQL-01 ~]# grep ‘numa‘ /etc/grub.conf 
        kernel /vmlinuz-2.6.32-220.el6.x86_64 ro root=UUID=c0618639-a967-4601-bca7-cc3b99c5c332 elevator=deadline rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD quiet SYSFONT=latarcyrheb-sun16 rhgb crashkernel=auto  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM numa=off
[root@MySQL-01 ~]# 

或者通过numactl命令将NUMA的内存分配策略修改为interleave

/usr/bin/numactl --interleave=all /usr/local/mysql-5.1.66/bin/mysqld_safe --defaults-file=/usr/local/mysql-5.1.66/my.cnf

这样就指定了MySQL启动时内存的分配策略是interleave

如果单机运行多个MySQL实例,可以将不同MySQL实例绑定到不同的CPU节点上,同时配置合适的MySQL内存参数,并且采用绑定的内存分配测试,强制在本地节点分配内存。

 

5.vm.swappiness调整

swappiness是操作系统控制物理内存交换出去的策略。它允许的值是一个百分比的值,最小为0,最大运行100,该值默认为60。vm.swappiness设置为0表示尽量少swap,100表示尽量将inactive的内存页交换出去。 
具体的说:当内存基本用满的时候,系统会根据这个参数来判断是把内存中很少用到的inactive 内存交换出去,还是释放数据的cache。cache中缓存着从磁盘读出来的数据,根据程序的局部性原理,这些数据有可能在接下来又要被读取;inactive 内存顾名思义,就是那些被应用程序映射着,但是“长时间”不用的内存。

我们可以利用vmstat看到inactive的内存的数量:

[root@MySQL-01 ~]# vmstat -an 1 5
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free  inact active   si   so    bi    bo   in   cs us sy id wa st
 0  0   4892 1194972 234208 492404    0    0     5    38   32   83  0  1 99  0  0
 0  0   4892 1194964 234208 492420    0    0     0     0   24   29  0  0 100  0  0
 0  0   4892 1194964 234208 492420    0    0     0     0   12   21  0  0 100  0  0
 0  0   4892 1194964 234208 492420    0    0     0     0   20   24  0  0 100  0  0
 0  0   4892 1194964 234208 492420    0    0     0     0   13   21  0  0 100  0  0
[root@MySQL-01 ~]# 

通过/proc/meminfo 你可以看到更详细的信息:

[root@MySQL-01 ~]# cat /proc/meminfo | grep -i inact 
Inactive:         234188 kB
Inactive(anon):     3228 kB
Inactive(file):   230960 kB
[root@MySQL-01 ~]# 

Linux中,内存可能处于三种状态:free,active和inactive。众所周知,Linux Kernel在内部维护了很多LRU列表用来管理内存,比如LRU_INACTIVE_ANON, LRU_ACTIVE_ANON, LRU_INACTIVE_FILE , LRU_ACTIVE_FILE, LRU_UNEVICTABLE。其中LRU_INACTIVE_ANON, LRU_ACTIVE_ANON用来管理匿名页,LRU_INACTIVE_FILE , LRU_ACTIVE_FILE用来管理page caches页缓存。系统内核会根据内存页的访问情况,不定时的将活跃active内存被移到inactive列表中,这些inactive的内存可以被交换到swap中去。 
一般来说,MySQL,特别是InnoDB管理内存缓存,它占用的内存比较多,不经常访问的内存也会不少,这些内存如果被Linux错误的交换出去了,将浪费很多CPU和IO资源。InnoDB自己管理缓存,cache的文件数据来说占用了内存,对InnoDB几乎没有任何好处。 
所以,我们在MySQL的服务器上最好设置vm.swappiness=0。

我们可以通过在sysctl.conf中添加一行:

[root@MySQL-01 ~]# echo "vm.swappiness = 0" >>/etc/sysctl.conf
[root@MySQL-01 ~]# sysctl -p

另外一种做法是innodb启用大内存页,也和上述方法有相同的效果,这里就不过多介绍了。

 

6.CPU优化

检查CPU是否开启了节能选项

[root@localhost ~]# grep -E ‘^model name|^cpu MHz‘ /proc/cpuinfo
model name      : Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz
cpu MHz         : 2266.602
model name      : Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz
cpu MHz         : 2266.602
model name      : Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz
cpu MHz         : 2266.602
model name      : Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz
cpu MHz         : 2266.602
model name      : Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz
cpu MHz         : 2266.602
model name      : Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz
cpu MHz         : 2266.602
model name      : Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz
cpu MHz         : 2266.602
model name      : Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz
cpu MHz         : 2266.602
[root@localhost ~]# 
如果发现CPU的频率跟它标称的频率不一样,那么就是开启了节能模式。
节能模式:操作系统和CPU硬件配合,系统不繁忙的时候,为了节约电能和降低温度,它会将CPU降频。对MySQL来说,可能是一个灾难。 为了保证MySQL能够充分利用CPU的资源,建议设置CPU为最大性能模式。这个设置可以在BIOS和操作系统中设置,当然,在BIOS中设置该选项更好,更彻底
 

7.内存分配算法的选择

默认的内存分配就是c的malloc 现在也出现许多优化的内存分配算法,例如: jemalloc & TCMalloc

以 TCMalloc 为例,它是 google-perftools工具中的一个(gperftools四个工具分别是:TCMalloc、heap-checker、heap- profiler 和 cpu-profiler),可以从 google.code 获得源码,安装过程不再多说,只使用 TCMalloc 的话,可以不编译其他三个工具,64位系统需要先安装依赖包 libunwind 。

TCMalloc 安装完成后执行以下命令:

[root@server02 ~]# echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local_lib.conf
[root@server02 ~]# /sbin/ldconfig

修改 mysql 启动脚本 mysqld_safe ,在 “# executing mysqld_safe” 行后添加一行:

export LD_PRELOAD="/usr/local/lib/libtcmalloc.so"

目的是在启动 mysql 前, 加载tcmalloc动态库。

现在重启 mysql 检查进程:

[root@server02 ~]# lsof -n | grep tcmalloc
mysqld    17890      root  mem       REG        8,7    1891417      20400 /usr/local/lib/libtcmalloc.so.4.2.4

可以看到 mysql 已经加载了 TCMalloc。

 

8.文件描述符

Linux - kernel 利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。对于不太繁忙的服务器,需要打开大量的文件,导致文件描述符数量限制过小,可能导致无法访问新的文件、或者连接受限。

查看当前文件描述符:

[root@server02 ~]# ulimit -n
1024
[root@server02 ~]# cat /proc/sys/fs/file-nr
544     0       101054

其中第一行结果表示当前文件描述符上限,第二行结果中第一个数表示当前系统已分配使用的打开文件描述符数,第二个数为分配后已释放的(目前已不再使用),第三个数等于file-max。

要修改文件描述符限制,可以在 /etc/security/limits.conf 中添加以下两行:

[root@server02 ~]# vim /etc/security/limits.conf
..........................
* soft nofile 10240
* hard nofile 10240

保存退出后,重新登录服务器,可以看到:

[root@server02 ~]# ulimit -n
10240

 

9.一点硬件Tips

(1)更多的内存:不奢求能把所有数据全部放入内存中,但是尽量让内存能放入库中热数据的 80% 。

(2)更快的CPU:更多的CPU并不总是能有立竿见影的效果(MySQL 5.6 可以利用到64个核,可 MySQL 每个 query 只能运行在一个CPU上),但是更快的CPU却是我们都需要的。

(3)更快的存储设备:很多时候IO能力都是 MySQL 的瓶颈,有SSD或者固态卡可供选择的话请不要犹豫。

(4)Raid卡:Raid 10 是我们的第一选择,而且请使用带电的Raid,启用WriteBack,这对于加速redo log ,binary log, data file都有好处。

 

参考文章:

http://www.cnblogs.com/gomysql/p/3643726.html

http://www.cnblogs.com/littlehb/archive/2013/04/14/3020336.html

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。