NUMA的取舍與優化設定
在os層numa關閉時,打開bios層的numa會影響性能,QPS會下降15-30%;
在bios層面numa關閉時,無論os層面的numa是否打開,都不會影響性能。
安裝numactl:
#yum install numactl -y
#numastat 等同于 cat /sys/devices/system/node/node0/numastat ,在/sys/devices/system/node/檔案夾中記錄系統中的所有記憶體節點的相關詳細資訊。 #numactl --hardware 列舉系統上的NUMA節點
#numactl --show 檢視綁定資訊
Redhat或者Centos系統中可以通過指令判斷bios層是否開啟numa
# grep -i numa /var/log/dmesg
如果輸出結果為: No NUMA configuration found
說明numa為disable,如果不是上面内容說明numa為enable,例如顯示:NUMA: Using 30 for the hash shift.
可以通過lscpu指令檢視機器的NUMA拓撲結構。
當發現numa_miss數值比較高時,說明需要對配置設定政策進行調整。例如将指定程序關聯綁定到指定的CPU上,進而提高記憶體命中率。
---------------------------------------------
現在的機器上都是有多個CPU和多個記憶體塊的。以前我們都是将記憶體塊看成是一大塊記憶體,所有CPU到這個共享記憶體的通路消息是一樣的。這就是之前普遍使用的SMP模型。但是随着處理器的增加,共享記憶體可能會導緻記憶體通路沖突越來越厲害,且如果記憶體通路達到瓶頸的時候,性能就不能随之增加。NUMA(Non-Uniform Memory Access)就是這樣的環境下引入的一個模型。比如一台機器是有2個處理器,有4個記憶體塊。我們将1個處理器和兩個記憶體塊合起來,稱為一個NUMA node,這樣這個機器就會有兩個NUMA node。在實體分布上,NUMA node的處理器和記憶體塊的實體距離更小,是以通路也更快。比如這台機器會分左右兩個處理器(cpu1, cpu2),在每個處理器兩邊放兩個記憶體塊(memory1.1, memory1.2, memory2.1,memory2.2),這樣NUMA node1的cpu1通路memory1.1和memory1.2就比通路memory2.1和memory2.2更快。是以使用NUMA的模式如果能盡量保證本node内的CPU隻通路本node内的記憶體塊,那這樣的效率就是最高的。
在運作程式的時候使用numactl -m和-physcpubind就能制定将這個程式運作在哪個cpu和哪個memory中。玩轉cpu-topology 給了一個表格,當程式隻使用一個node資源和使用多個node資源的比較表(差不多是38s與28s的差距)。是以限定程式在numa node中運作是有實際意義的。
但是呢,話又說回來了,制定numa就一定好嗎?--numa的陷阱。SWAP的罪與罰文章就說到了一個numa的陷阱的問題。現象是當你的伺服器還有記憶體的時候,發現它已經在開始使用swap了,甚至已經導緻機器出現停滞的現象。這個就有可能是由于numa的限制,如果一個程序限制它隻能使用自己的numa節點的記憶體,那麼當自身numa node記憶體使用光之後,就不會去使用其他numa node的記憶體了,會開始使用swap,甚至更糟的情況,機器沒有設定swap的時候,可能會直接當機!是以你可以使用numactl --interleave=all來取消numa node的限制。
綜上所述得出的結論就是,根據具體業務決定NUMA的使用。
如果你的程式是會占用大規模記憶體的,你大多應該選擇關閉numa node的限制(或從硬體關閉numa)。因為這個時候你的程式很有幾率會碰到numa陷阱。
另外,如果你的程式并不占用大記憶體,而是要求更快的程式運作時間。你大多應該選擇限制隻通路本numa node的方法來進行處理。
---------------------------------------------------------------------
核心參數overcommit_memory :
它是 記憶體配置設定政策
可選值:0、1、2。
0:表示核心将檢查是否有足夠的可用記憶體供應用程序使用;如果有足夠的可用記憶體,記憶體申請允許;否則,記憶體申請失敗,并把錯誤傳回給應用程序。
1:表示核心允許配置設定所有的實體記憶體,而不管目前的記憶體狀态如何。
2:表示核心允許配置設定超過所有實體記憶體和交換空間總和的記憶體
核心參數zone_reclaim_mode:
可選值0、1
a、當某個節點可用記憶體不足時:
1、如果為0的話,那麼系統會傾向于從其他節點配置設定記憶體
2、如果為1的話,那麼系統會傾向于從本地節點回收Cache記憶體多數時候
b、Cache對性能很重要,是以0是一個更好的選擇
----------------------------------------------------------------------
mongodb的NUMA問題
mongodb日志顯示如下:
WARNING: You are running on a NUMA machine.
We suggest launching mongod like this to avoid performance problems:
numactl –interleave=all mongod [other options]
解決方案,臨時修改numa記憶體配置設定政策為 interleave=all (在所有node節點進行交織配置設定的政策):
1.在原啟動指令前面加numactl –interleave=all
如# numactl --interleave=all ${MONGODB_HOME}/bin/mongod --config conf/mongodb.conf
2.修改核心參數
echo 0 > /proc/sys/vm/zone_reclaim_mode ; echo "vm.zone_reclaim_mode = 0" >> /etc/sysctl.conf
----------------------------------------------------------------------
一、NUMA和SMP
NUMA和SMP是兩種CPU相關的硬體架構。在SMP架構裡面,所有的CPU争用一個總線來通路所有記憶體,優點是資源共享,而缺點是總線争用激烈。随着PC伺服器上的CPU數量變多(不僅僅是CPU核數),總線争用的弊端慢慢越來越明顯,于是Intel在Nehalem CPU上推出了NUMA架構,而AMD也推出了基于相同架構的Opteron CPU。
NUMA最大的特點是引入了node和distance的概念。對于CPU和記憶體這兩種最寶貴的硬體資源,NUMA用近乎嚴格的方式劃分了所屬的資源組(node),而每個資源組内的CPU和記憶體是幾乎相等。資源組的數量取決于實體CPU的個數(現有的PC server大多數有兩個實體CPU,每個CPU有4個核);distance這個概念是用來定義各個node之間調用資源的開銷,為資源排程優化算法提供資料支援。
二、NUMA相關的政策
1、每個程序(或線程)都會從父程序繼承NUMA政策,并配置設定有一個優先node。如果NUMA政策允許的話,程序可以調用其他node上的資源。
2、NUMA的CPU配置設定政策有cpunodebind、physcpubind。cpunodebind規定程序運作在某幾個node之上,而physcpubind可以更加精細地規定運作在哪些核上。
3、NUMA的記憶體配置設定政策有localalloc、preferred、membind、interleave。
localalloc規定程序從目前node上請求配置設定記憶體;
而preferred比較寬松地指定了一個推薦的node來擷取記憶體,如果被推薦的node上沒有足夠記憶體,程序可以嘗試别的node。
membind可以指定若幹個node,程序隻能從這些指定的node上請求配置設定記憶體。
interleave規定程序從指定的若幹個node上以RR(Round Robin 輪詢排程)算法交織地請求配置設定記憶體。
因為NUMA預設的記憶體配置設定政策是優先在程序所在CPU的本地記憶體中配置設定,會導緻CPU節點之間記憶體配置設定不均衡,當某個CPU節點的記憶體不足時,會導緻swap産生,而不是從遠端節點配置設定記憶體。這就是所謂的swap insanity 現象。
MySQL采用了線程模式,對于NUMA特性的支援并不好,如果單機隻運作一個MySQL執行個體,我們可以選擇關閉NUMA,關閉的方法有三種:
1.硬體層,在BIOS中設定關閉
2.OS核心,啟動時設定numa=off;
3.可以用numactl指令将記憶體配置設定政策修改為interleave(交叉)。
如果單機運作多個MySQL執行個體,我們可以将MySQL綁定在不同的CPU節點上,并且采用綁定的記憶體配置設定政策,強制在本節點内配置設定記憶體,這樣既可以充分利用硬體的NUMA特性,又避免了單執行個體MySQL對多核CPU使用率不高的問題
三、NUMA和swap的關系
可能大家已經發現了,NUMA的記憶體配置設定政策對于程序(或線程)之間來說,并不是公平的。在現有的Redhat Linux中,localalloc是預設的NUMA記憶體配置設定政策,這個配置選項導緻資源獨占程式很容易将某個node的記憶體用盡。而當某個node的記憶體耗盡時,Linux又剛好将這個node配置設定給了某個需要消耗大量記憶體的程序(或線程),swap就妥妥地産生了。盡管此時還有很多page cache可以釋放,甚至還有很多的free記憶體。
四、解決swap問題
雖然NUMA的原理相對複雜,實際上解決swap卻很簡單:隻要在啟動MySQL之前使用numactl –interleave來修改NUMA政策即可。
值得注意的是,numactl這個指令不僅僅可以調整NUMA政策,也可以用來檢視目前各個node的資源使用情況,是一個很值得研究的指令。
一、CPU
首先從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和作業系統中設定,當然,在BIOS中設定該選項更好,更徹底。由于各種BIOS類型的差別,設定為CPU為最大性能模式千差萬别,我們這裡就不具體展示怎麼設定了。
然後我們看看記憶體方面,我們有哪些可以優化的。
i) 我們先看看numa
非一緻存儲通路結構 (NUMA : Non-Uniform Memory Access) 也是最新的記憶體管理技術。它和對稱多處理器結構 (SMP : Symmetric Multi-Processor) 是對應的。簡單的隊别如下:
如圖所示,詳細的NUMA資訊我們這裡不介紹了。但是我們可以直覺的看到:SMP通路記憶體的都是代價都是一樣的;但是在NUMA架構下,本地記憶體的通路和非 本地記憶體的通路代價是不一樣的。對應的根據這個特性,作業系統上,我們可以設定程序的記憶體配置設定方式。目前支援的方式包括:
--interleave=nodes
--membind=nodes
--cpunodebind=nodes
--physcpubind=cpus
--localalloc
--preferred=node
簡而言之,就是說,你可以指定記憶體在本地配置設定,在某幾個CPU節點配置設定或者輪詢配置設定。除非 是設定為--interleave=nodes輪詢配置設定方式,即記憶體可以在任意NUMA節點上配置設定這種方式以外。其他的方式就算其他NUMA節點上還有内 存剩餘,Linux也不會把剩餘的記憶體配置設定給這個程序,而是采用SWAP的方式來獲得記憶體。有經驗的系統管理者或者DBA都知道SWAP導緻的資料庫性能 下降有多麼坑爹。
是以最簡單的方法,還是關閉掉這個特性。
關閉特性的方法,分别有:可以從BIOS,作業系統,啟動程序時臨時關閉這個特性。
a) 由于各種BIOS類型的差別,如何關閉NUMA千差萬别,我們這裡就不具體展示怎麼設定了。
b) 在作業系統中關閉,可以直接在/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盡量回收記憶體。
c) 啟動MySQL的時候,關閉NUMA特性:
numactl --interleave=all mysqld
當然,最好的方式是在BIOS中關閉。
ii) 我們再看看vm.swappiness。
vm.swappiness是作業系統控制實體記憶體交換出去的政策。它允許的值是一個百分比的值,最小為0,最大運作100,該值預設為60。vm.swappiness設定為0表示盡量少swap,100表示盡量将inactive的記憶體頁交換出去。
具體的說:當記憶體基本用滿的時候,系統會根據這個參數來判斷是把記憶體中很少用到的inactive 記憶體交換出去,還是釋放資料的cache。cache中緩存着從磁盤讀出來的資料,根據程式的局部性原理,這些資料有可能在接下來又要被讀 取;inactive 記憶體顧名思義,就是那些被應用程式映射着,但是 長時間 不用的記憶體。
我們可以利用vmstat看到inactive的記憶體的數量:
#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
1 0 0 27522384 326928 1704644 0 0 0 153 11 10 0 0 100 0 0
0 0 0 27523300 326936 1704164 0 0 0 74 784 590 0 0 100 0 0
0 0 0 27523656 326936 1704692 0 0 8 8 439 1686 0 0 100 0 0
0 0 0 27524300 326916 1703412 0 0 4 52 198 262 0 0 100 0 0
通過/proc/meminfo 你可以看到更詳細的資訊:
#cat /proc/meminfo | grep -i inact
Inactive: 326972 kB
Inactive(anon): 248 kB
Inactive(file): 326724 kB
這裡我們對不活躍inactive記憶體進一步深入讨論。 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=1或0