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
作者:Atlas
出處:Atlas的部落格 http://www.cnblogs.com/gomysql
您的支援是對部落客最大的鼓勵,感謝您的認真閱讀。本文版權歸作者所有,歡迎轉載,但請保留該聲明。如果您需要技術支援,本人亦提供有償服務。