效能調優之MySQL篇四:MySQL配置定位以及優化
一、CPU最大效能模式
cpu利用特點
-
5.1 最高可用4個核
-
5.5 最高可用24核
-
5.6 最高可用64核心
-
一次query對應一個邏輯CPU
你仔細檢查的話,有些伺服器上會有的一個有趣的現象:你cat /proc/cpuinfo時,會發現CPU的頻率竟然跟它標稱的頻率不一樣:
#cat /proc/cpuinfo processor : 5 model name : Intel(R) Xeon(R) CPU E5-2620 0 @2.00GHz ... cpu MHz : 1200.000
這個是Intel E5-2620的CPU,他是2.00G * 24的CPU,但是,我們發現第5顆CPU的頻率為1.2G
原因:其實都源於CPU最新的技術:節能模式。作業系統和CPU硬體配合,系統不繁忙的時候,為了節約電能和降低溫度,它會將CPU降頻。這對環保人士和抵制地球變暖來說是一個福音,但是對MySQL來說,可能是一個災難。
為了保證MySQL能夠充分利用CPU的資源,建議設定CPU為最大效能模式,這個設定可以在BIOS和作業系統中設定
二、關閉numa
非一致儲存訪問結構 (NUMA : Non-Uniform Memory Access) 也是最新的記憶體管理技術。它和對稱多處理器結構 (SMP : Symmetric Multi-Processor) 是對應的。簡單的隊別如圖:
但是我們可以直觀的看到:SMP訪問記憶體的都是代價都是一樣的;但是在NUMA架構下,本地記憶體的訪問和非本地記憶體的訪問代價是不一樣的。對應的根據這個特性,作業系統上,我們可以設定程序的記憶體分配方式。目前支援的方式包括:
--interleave=nodes --membind=nodes --cpunodebind=nodes --physcpubind=cpus --localalloc --preferred=node
簡而言之,就是說,你可以指定記憶體在本地分配,在某幾個CPU節點分配或者輪詢分配。除非是設定為--interleave=nodes輪詢分配方式,即記憶體可以在任意NUMA節點上分配這種方式以外。
其他的方式就算其他NUMA節點上還有記憶體剩餘,Linux也不會把剩餘的記憶體分配給這個程序,而是採用SWAP的方式來獲得記憶體。有經驗的系統管理員或者DBA都知道SWAP導致的資料庫效能下降 ,所以最簡單的方法,還是關閉掉這個特性
關閉特性的方法,分別有:
-
可以從BIOS設定關閉
-
啟動MySQL的時候,關閉NUMA特性 numactl --interleave=all mysqld &
-
OS核心,啟動時設定numa=off
-
在作業系統中關閉,可以直接在/etc/grub.conf的kernel行最後新增numa=off,如下所示
kernel /vmlinuz-2.6.32-220.el6.x86_64 ro root=/dev/mapper/VolGroup-root rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=VolGroup/root rd_NO_MD quiet SYSFONT=latarcyrheb-sun16 rhgb crashkernel=auto rd_LVM_LV=VolGroup/swap rhgb crashkernel=auto quiet KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM numa=off
設定vm.zone_reclaim_mode=0儘量回收記憶體
三、關閉vm.swappiness
vm.swappiness是作業系統控制實體記憶體交換出去的策略。它允許的值是一個百分比的值,最小為0,最大執行100,該值預設為60
vm.swappiness設定為0表示儘量少swap,100表示儘量將inactive的記憶體頁交換出去。
當記憶體基本用滿的時候,系統會根據這個引數來判斷是把記憶體中很少用到的inactive 記憶體交換出去,還是釋放資料的cache。cache中快取著從磁碟讀出來的資料,根據程式的區域性性原理,這些資料有可能在接下來又要被讀取;inactive 記憶體顧名思義,就是那些被應用程式對映著,但是“長時間”不用的記憶體。
我們可以檢視inactive的記憶體的數量:
[[email protected] ~]# vmstat -an 1 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 61432 1533944 1553788 3190400 0 0 9 216 0 0 5 2 88 4 0 0 0 61432 1533564 1553900 3190568 0 0 0 120 616 349 2 1 97 1 0 1 0 61432 1533068 1553844 3191096 0 0 0 5748 1604 455 1 1 95 3 0 2 1 61432 1531952 1553812 3191984 0 0 172 700 1033 416 2 1 74 23 0 [[email protected] ~]# cat /proc/meminfo | grep -i inact Inactive: 1557236 kB Inactive(anon): 279888 kB Inactive(file): 1277348 kB
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中新增一行:
echo "vm.swappiness = 0" >>/etc/sysctl.conf
四、檔案系統
建議在檔案系統的mount引數上加上noatime,nobarrier兩個選項
用noatime mount的話,檔案系統在程式訪問對應的檔案或者資料夾時,不會更新對應的access time。一般來說,Linux會給檔案記錄了三個時間,change time, modify time和access time。
我們可以通過stat來檢視檔案的三個時間:
[[email protected] ~]# stat mysql-test.sh File: `mysql-test.sh' Size: 970 Blocks: 8 IO Block: 4096 regular file Device: ca01h/51713d Inode: 33883111 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2015-12-16 19:55:58.962535495 +0800 Modify: 2015-12-11 09:15:38.410196493 +0800 Change: 2015-12-11 09:15:38.493196460 +0800
-
access time指檔案最後一次被讀取的時間
-
modify time指的是檔案的文字內容最後發生變化的時間
-
change time指的是檔案的inode最後發生變化(比如位置、使用者屬性、組屬性等)的時間
一般來說,檔案都是讀多寫少,而且我們也很少關心某一個檔案最近什麼時間被訪問了。所以,我們建議採用noatime選項,這樣檔案系統不記錄access time,避免浪費資源
現在的很多檔案系統會在資料提交時強制底層裝置重新整理cache,避免資料丟失,稱之為write barriers。但是,其實我們資料庫伺服器底層儲存裝置要麼採用RAID卡,RAID卡本身的電池可以掉電保護;要麼採用Flash卡,它也有自我保護機制,保證資料不會丟失。所以我們可以安全的使用nobarrier掛載檔案系統。設定方法如下: 對於ext3, ext4和 reiserfs檔案系統可以在mount時指定barrier=0;對於xfs可以指定nobarrier選項
檔案系統上還有一個提高IO的優化萬能鑰匙,那就是deadline
在Flash技術之前,我們都是使用機械磁碟儲存資料的,機械磁碟的尋道時間是影響它速度的最重要因素,直接導致它的每秒可做的IO(IOPS)非常有限,為了儘量排序和合並多個請求,以達到一次尋道能夠滿足多次IO請求的目的,Linux檔案系統設計了多種IO排程策略,已適用各種場景和儲存裝置。
Linux的IO排程策略包括:Deadline scheduler,Anticipatory scheduler,Completely Fair Queuing(CFQ),NOOP
CFQ是Linux核心2.6.18之後的預設排程策略,它聲稱對每一個 IO 請求都是公平的,這種排程策略對大部分應用都是適用的。但是如果資料庫有兩個請求,一個請求3次IO,一個請求10000次IO,由於絕對公平,3次IO的這個請求都需要跟其他10000個IO請求競爭,可能要等待上千個IO完成才能返回,導致它的響應時間非常慢。並且如果在處理的過程中,又有很多IO請求陸續傳送過來,部分IO請求甚至可能一直無法得到排程被“餓死”。而deadline兼顧到一個請求不會在佇列中等待太久導致餓死,對資料庫這種應用來說更加適用
CFQ與Deadline,NOOP效能差異很小,但是一旦有大的連續IO,CFQ可能會造成小IO的響應延時增加,所以資料庫環境建議修改為deadline演算法,表現更穩定。我們的環境統一使用deadline演算法。
IO排程演算法都是基於磁碟設計,所以減少磁頭移動是最重要的考慮因素之一,但是使用Flash儲存裝置之後,不再需要考慮磁頭移動的問題,可以使用NOOP演算法。NOOP的含義就是NonOperation,意味著不會做任何的IO優化,完全按照請求來FIFO的方式來處理IO。
減少預讀:/sys/block/sdb/queue/read_ahead_kb,預設128,調整為16
增大佇列:/sys/block/sdb/queue/nr_requests,預設128,調整為512
實時設定,我們可以通過
echo deadline >/sys/block/sda/queue/scheduler
我們也可以直接在/etc/grub.conf的kernel行最後新增elevator=deadline來永久生效
五、RAID優化
關閉讀cache:RAID卡上的cache容量有限,我們選擇direct方式讀取資料,從而忽略讀cache。
關閉預讀:RAID卡的預讀功能對於隨機IO幾乎沒有任何提升,所以將預讀功能關閉。
關閉磁碟cache:一般情況下,如果使用RAID,系統會預設關閉磁碟的cache,也可以用命令強制關閉。
以上設定都可以通過RAID卡的命令列來完成
開啟BBWC
RAID卡都有寫cache(Battery Backed Write Cache),寫cache對IO效能的提升非常明顯,因為掉電會丟失資料,所以必須由電池提供支援。電池會定期充放電,一般為90天左右,當發現電量低於某個閥值時,會將寫cache策略從writeback置為writethrough,相當於寫cache會失效,這時如果系統有大量的IO操作,可能會明顯感覺到IO響應速度變慢。目前,新的RAID卡內建了flash儲存,掉電後會將寫cache的資料寫入flash中,這樣就可以保證資料永不丟失,但依然需要電池的支援。
解決方案有兩種:1.人工觸發充放電,可以選擇在業務低谷時做,降低對應用的影響;2.設定寫cache策略為force write back,即使電池失效,也保持寫cache策略為writeback,這樣存在掉電後丟失資料的風險。
六、Flashcache
建立flashcache:flashcache_create -b 4k cachedev /dev/sdc /dev/sdb
指定flashcache的block大小與Percona的page大小相同。
Flashcache引數設定:
flashcache.fast_remove = 1:開啟fast remove特性,關閉機器時,無需將cache中的髒塊寫入磁碟 flashcache.reclaim_policy = 1:髒塊刷出策略,0:FIFO,1:LRU flashcache.dirty_thresh_pct = 90:flashcache上每個hash set上的髒塊閥值 flashcache.cache_all = 1:cache所有內容,可以用黑名單過濾 flashecache.write_merge = 1:開啟寫入合併,提升寫磁碟的效能
七、IOPS
磁碟尋道能力(磁碟I/O),以目前高轉速SCSI硬碟(7200轉/秒)為例,這種硬碟理論上每秒尋道7200次,這是物理特性決定的,沒有辦法改變。 MySQL每秒鐘都在進行大量、複雜的查詢操作,對磁碟的讀寫量可想而知。所以,通常認為磁碟I/O是制約MySQL效能的最大因素之一,對於日均訪問量 在100萬PV以上的Discuz!論壇,由於磁碟I/O的制約,MySQL的效能會非常低下!解決這一制約因素可以考慮以下幾種解決方案: 使用RAID-0+1磁碟陣列,注意不要嘗試使用RAID-5,MySQL在RAID-5磁碟陣列上的效率不會像你期待的那樣快
innodb_page_size:如果使用fusionio,4K的效能最好;使用SAS磁碟,設定為8K。如果全表掃描很多,可以設定為16K。比較小的page size,可以提升cache的命中率。 innodb_adaptive_checkpoint:如果使用fusionio,設定為3,提高重新整理頻率到0.1秒;使用SAS磁碟,設定為2,採用estimate方式重新整理髒頁。 innodb_io_capacity:根據IOPS能力設定,使用fuionio可以設定10000以上。 innodb_flush_neighbor_pages = 0:針對fusionio或者SSD,因為隨機IO足夠好,所以關閉此功能。 innodb_flush_method=ALL_O_DIRECT:公版的MySQL只能將資料庫檔案讀寫設定為DirectIO,對於Percona可以將log和資料檔案設定為direct方式讀寫。但是我不確定這個引數對於innodb_flush_log_at_trx_commit的影響, innodb_read_io_threads = 1:設定預讀執行緒設定為1,因為線性預讀的效果並不明顯,所以無需設定更大。 innodb_write_io_threads = 16:設定寫執行緒數量為16,提升寫的能力。 innodb_fast_checksum = 1:開啟Fast checksum特性。