Linux上跑MySQL優化技巧


1.禁止操作系統更新文件的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)重新mount文件系統使其修改生效:

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

 

2.調整I/O調度算法

詳細說明請參考前面文章提到的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 ~]# 

 

3.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內存參數,並且采用綁定的內存分配測試,強制在本地節點分配內存。

 

4.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中添加一行(如果你的內核版本是2.6.32-303.el6及以后,請設置vm.swappiness = 1):

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

另外一種做法是innodb啟用大內存頁,也和上述方法有相同的效果。具體請參考前面文章提到的InnoDB啟用大內存頁

 

5.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的頻率跟它標稱的頻率不一樣,那么就是開啟了節能模式。
可以使用下面命令關閉:
for CPUFREQ in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do [ -f $CPUFREQ ] || continue; echo -n performance > $CPUFREQ; done

節能模式:操作系統和CPU硬件配合,系統不繁忙的時候,為了節約電能和降低溫度,它會將CPU降頻。對MySQL來說,可能是一個災難。 為了保證MySQL能夠充分利用CPU的資源,建議設置CPU為最大性能模式。這個設置可以在BIOS和操作系統中設置,當然,在BIOS中設置該選項更好。

 

參考資料:

http://www.mysqlperformanceblog.com/2013/12/07/linux-performance-tuning-tips-mysql/

http://www.benjaminathawes.com/2011/11/09/determining-numa-node-boundaries-for-modern-cpus/

http://www.experts-exchange.com/OS/Linux/A_3492-Avoiding-CPU-speed-scaling-in-modern-Linux-distributions-Running-CPU-at-full-speed-Tips.html

http://dikar.iteye.com/blog/776563

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM