NUMA 架構與 資料庫

babyyellow發表於2012-12-14

現代主機,尤其是多核系統,已經成為標準配置了,

什麼事NUMA ?

Non  Uniform  Memory Access   非一致性記憶體訪問架構 。

現在的X86-64系統架構都是這樣的了。

就是記憶體跟cpu 有一個繫結。比如我們的系統  64g記憶體 2*8cpu

那麼 就是 兩個cpu 每個分的32g 記憶體

cpu 1 上的程式、執行緒,優先使用本地的32g 記憶體,如果要訪問 cup2 上的記憶體,就會花很大的力氣。
效能會下降。


這裡就引入了一個問題:

比如我們的oracle 系統,如果在linux 架構上,分配的記憶體大於32G
 就可能帶來記憶體訪問方面的問題。

PG ,mysql 也有這個問題。

numa  的記憶體訪問策略,預設的是local  ,也就是優先使用本地記憶體, 這裡就存在一個問題,

數 據庫 pg oracle 是多程式的,如果分配的sga  接近或者超過32g ,新的程式在同一個物理cpu 啟動的時候,發現記憶體不夠了,就有可能會導致swap ,而實際上,另一個物理cpu 的記憶體還沒有用完,還可以在另一個物理cpu上繫結的記憶體上,繼續分配記憶體。

假設,我們啟動資料庫,sga 分配在cpu 1上繫結的記憶體,而某一個連線,是在cup2 上執行,
那麼這個程式訪問sga 的時候,效能就會比在cpu 1 上執行的程式低很多,同樣的在cpu1上執行的程式,可能更容易發生swapness 。



我們目前的問題:


我們的mysql 目前是採用的單機多例項的方式執行,每個資料庫例項配置的記憶體都不是很大,基本不會發生這個問題。

oracle 與 pg 資料庫 ,則可能存在我們上面提到的問題。

怎麼避免呢? 單機單例項的資料庫,建議關閉numa 策略。

主機OS層面 提供了一些工具來幫助我們實施。

一個是numastat   一個是numactl

看看先:

numastat  就是列印系統目前的numa情況:

[root@pgsql-238-181 ~]# numastat
                           node0           node1
numa_hit              7215446485      7503909011
numa_miss              850409592       149660507
numa_foreign           149660507       850409592
interleave_hit             13764           13784
local_node            7215347684      7503856800
other_node             850508393       149712718

各個欄位的含義 看 man page 吧。



numactl   可以用來改變系統的策略

預設是default   , 

[root@pgsql-238-181 ~]# numactl  --show
policy: default                                            ## numa策略 預設
preferred node: current                               ##  記憶體分配方式,在當前節點上分配
physcpubind: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15    ## cpu 編號
cpubind: 0 1                                                              ## 物理cpu ,我們的是兩個cpu 所以為0 1
nodebind: 0 1                                                            ## 節點繫結,  兩個物理cpu 分為連個節點
membind: 0 1                                                             ##  記憶體繫結, 兩個對應到前面的nodebind
[root@pgsql-238-181 ~]#
[root@pgsql-238-181 ~]# numactl  --hardware
available: 2 nodes (0-1)                                                  ## 可用節點
node 0 cpus: 0 1 2 3 8 9 10 11                                       ## node 0 上cpu
node 0 size: 16372 MB                                                   ##  node 0 上分配的記憶體大小 16g
node 0 free: 475 MB                                                        ##  node 0 上空閒記憶體   475m
node 1 cpus: 4 5 6 7 12 13 14 15                                    ## 下面是node 1 的情況,同上
node 1 size: 16384 MB
node 1 free: 1188 MB
node distances:                                                              ##  node 間 的距離,這個一個度量值,沒有實際意義。
node   0   1
  0:  10  21                                               ##  這個矩形 說明的是 ,node 0 的上cpu 訪問node 0 上分配的記憶體,需要的權重,
  1:  21  10                                                ##      或者距離 是10  , 如果訪問node 1 上的分配的記憶體的權重或者距離是21  ,
                                                                 ##     node 1 上的cpu 也一樣, 訪問本地,是10 訪問對方是21

從上面可見,訪問異地的記憶體,開銷是訪問本地的兩倍多。 


numactl  的更多細節  檢視  man page 


針對我們的資料庫主機,我們應該採用什麼策略呢?

針對我們上面的提出的問題,我們建議採用 interleave  模式。  即 交叉分配,這樣基本可以做到記憶體平均的分配到兩個node 裡,
每個程式, 訪問本地與訪問異地記憶體的比例是1:1 。

基本可以可以避免我們前面說到的,系統有大量記憶體的時候,還發生swap 。

怎麼用呢, 程式一旦啟動就不會再受到numa策略的影響了,所以應該在啟動程式的時候,指定  numa 策略。

需要修改  啟動指令碼。

增加   /usr/bin/numactl --interleave all   $CMD 

例如PG資料庫   numactl  --interleave all   pg_ctl start 

我們看看程式的分部情況:

more   /proc/26929/numa_maps
00400000 interleave:0-1 file=/data/postgresql-9.1.4/bin/postgres mapped=217 mapmax=6 active=199 N0=189 N1=28
00ad9000 interleave:0-1 file=/data/postgresql-9.1.4/bin/postgres anon=12 dirty=12 mapmax=6 N0=6 N1=6
00ae5000 interleave:0-1 anon=15 dirty=15 mapmax=6 N0=8 N1=7
02a50000 interleave:0-1 heap anon=50 dirty=50 mapmax=6 N0=26 N1=24
34bda00000 interleave:0-1 file=/lib64/ld-2.12.so mapped=28 mapmax=49 N0=28
34bdc1f000 interleave:0-1 file=/lib64/ld-2.12.so anon=1 dirty=1 mapmax=6 N1=1
34bdc20000 interleave:0-1 file=/lib64/ld-2.12.so anon=1 dirty=1 N0=1
34bdc21000 interleave:0-1 anon=1 dirty=1 mapmax=4 N1=1


接下來的事情,就是安排修改主機的啟動指令碼了。






來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/133735/viewspace-751095/,如需轉載,請註明出處,否則將追究法律責任。

相關文章