以下是對NUMA和cgroup的初次實踐分享,僅供參考。
3、啓動
/etc/init.d/cgconfig restart
4、任務使用
killall -9 chunk_server
cgexec -g memory,cpuset:chunk_server /usr/local/gfs/bin/gfs_chunk_server_daemon.sh
killall -9 vip_cdn
cgexec -g memory,cpuset:other /usr/local/vip_cdn/bin/monitor.sh
詳細介紹請參考:https://access.redhat.com/site/documentation/zh-CN/Red_Hat_Enterprise_Linux/6/html/Resource_Management_Guide/
一、線上程序現象
最近在不少os6.4的系統上發現機器負載較大,部分cpu使用率很高,但部分cpu使用率很低;物理內存很空閒,使用率很低,但swap使用了很多;某些程序因分配不到內存而報錯等現象。更爲嚴重我的發現有啓動iptables都報錯失敗的情況,如下:
[root@abc tmp]# /etc/init.d/iptables start
iptables: Applying firewall rules: iptables-restore: line 31 failed
[FAILED]
[root@abc tmp]# tail /var/log/messages
Aug 14 00:21:19 abc kernel: Swap cache stats: add 386347, delete 385412, find 747707/754322
Aug 14 00:21:19 abc kernel: Free swap = 20167792kB
Aug 14 00:21:19 abc kernel: Total swap = 20971512kB
Aug 14 00:21:19 abc kernel: 4194303 pages RAM
Aug 14 00:21:19 abc kernel: 115322 pages reserved
Aug 14 00:21:19 abc kernel: 437874 pages shared
Aug 14 00:21:19 abc kernel: 3591085 pages non-shared
Aug 14 00:21:19 abc kernel: Unable to create nf_conn slab cache
Aug 14 00:21:20 abc modprobe: FATAL: Error inserting xt_state (/lib/modules/2.6.32-358.14.1.el6.x86_64/kernel/net/netfilter/xt_state.ko): Cannot allocate memory
Aug 14 00:21:47 abc kernel: nf_conntrack version 0.5.0 (16384 buckets, 65536 max)
[root@abc tmp]# free -m
total used free shared buffers cached
Mem: 15933 15768 165 0 58 11429
-/+ buffers/cache: 4280 11652
Swap: 20479 784 19695
此時mem和swap都有空餘,但還是Cannot allocate memory。經過查找資料這是NUMA導致的。
二、NUMA簡單介紹
NUMA是多核心CPU架構中的一種,其全稱爲Non-Uniform Memory Access(非同一內存),簡單來說就是在多核心CPU中,機器的物理內存是分配給各個核的,每個核訪問分配給自己的內存會比訪問分配給其它核的內存要快;【 從系統架構來說,目前的主流企業服務器基本可以分爲三類:SMP (Symmetric Multi Processing,對稱多處理架構),NUMA (Non-Uniform Memory Access,非一致存儲訪問架構),和MPP (Massive Parallel Processing,海量並行處理架構)。三種架構各有特點,SMP架構:所有cpu以平等代價訪問memory且共享系統總線,系統總線可能成爲性能瓶頸且不易擴展;MPP架構:邏輯上劃分爲多個node且每個node上的cpu訪問自己本地資源,擴展性好,node間數據交換難;NUMA架構介於前兩者之間;詳細介紹可以網上參考下】
最近在不少os6.4的系統上發現機器負載較大,部分cpu使用率很高,但部分cpu使用率很低;物理內存很空閒,使用率很低,但swap使用了很多;某些程序因分配不到內存而報錯等現象。更爲嚴重我的發現有啓動iptables都報錯失敗的情況,如下:
[root@abc tmp]# /etc/init.d/iptables start
iptables: Applying firewall rules: iptables-restore: line 31 failed
[FAILED]
[root@abc tmp]# tail /var/log/messages
Aug 14 00:21:19 abc kernel: Swap cache stats: add 386347, delete 385412, find 747707/754322
Aug 14 00:21:19 abc kernel: Free swap = 20167792kB
Aug 14 00:21:19 abc kernel: Total swap = 20971512kB
Aug 14 00:21:19 abc kernel: 4194303 pages RAM
Aug 14 00:21:19 abc kernel: 115322 pages reserved
Aug 14 00:21:19 abc kernel: 437874 pages shared
Aug 14 00:21:19 abc kernel: 3591085 pages non-shared
Aug 14 00:21:19 abc kernel: Unable to create nf_conn slab cache
Aug 14 00:21:20 abc modprobe: FATAL: Error inserting xt_state (/lib/modules/2.6.32-358.14.1.el6.x86_64/kernel/net/netfilter/xt_state.ko): Cannot allocate memory
Aug 14 00:21:47 abc kernel: nf_conntrack version 0.5.0 (16384 buckets, 65536 max)
[root@abc tmp]# free -m
total used free shared buffers cached
Mem: 15933 15768 165 0 58 11429
-/+ buffers/cache: 4280 11652
Swap: 20479 784 19695
此時mem和swap都有空餘,但還是Cannot allocate memory。經過查找資料這是NUMA導致的。
二、NUMA簡單介紹
NUMA是多核心CPU架構中的一種,其全稱爲Non-Uniform Memory Access(非同一內存),簡單來說就是在多核心CPU中,機器的物理內存是分配給各個核的,每個核訪問分配給自己的內存會比訪問分配給其它核的內存要快;【 從系統架構來說,目前的主流企業服務器基本可以分爲三類:SMP (Symmetric Multi Processing,對稱多處理架構),NUMA (Non-Uniform Memory Access,非一致存儲訪問架構),和MPP (Massive Parallel Processing,海量並行處理架構)。三種架構各有特點,SMP架構:所有cpu以平等代價訪問memory且共享系統總線,系統總線可能成爲性能瓶頸且不易擴展;MPP架構:邏輯上劃分爲多個node且每個node上的cpu訪問自己本地資源,擴展性好,node間數據交換難;NUMA架構介於前兩者之間;詳細介紹可以網上參考下】
查看是否支持numa及其numa信息:
[root@abc tmp]# numactl --show
policy: default //當前numa策略爲default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7
cpubind: 0 1
nodebind: 0 1
membind: 0 1 //以上爲可供綁定的cpu mem node等資源
[root@abc tmp]# numactl --hardware
available: 2 nodes (0-1) //表示有兩個可用節點
node 0 cpus: 0 2 4 6
node 0 size: 8192 MB
node 0 free: 2904 MB //節點0包含的cpu及其內存使用情況(本地資源情況)
node 1 cpus: 1 3 5 7
node 1 size: 8179 MB
node 1 free: 4220 MB //節點1
node distances:
node 0 1
0: 10 20
1: 20 10 //節點0訪問節點0即本地資源的代價是10,節點0訪問節點1的資源代價是20(訪問本地資源比遠程快)
在Linux上NUMA API支持四種內存分配策略:
1. 缺省(default) - 總是在本地節點分配(分配在當前線程運行的節點上)
2. 綁定(bind) - 分配到指定節點上
3. 交織(interleave) - 在所有節點或者指定的節點上交織分配
4. 優先(preferred) - 在指定節點上分配,失敗則在其他節點上分配
綁定和優先的區別是,在指定節點上分配失敗時(如無足夠內存),綁定策略會報告分配失敗,而優先策略會嘗試在其他節點上進行分配。強制使用綁定有可能會導致前期的內存短缺,並引起大量換頁。缺省的策略是更加普適的優先策略。
三、使用cgroup軟件對資源進行分配控制與隔離
Cgroups是control groups的縮寫,是Linux內核提供的一種可以限制、記錄、隔離進程組(process groups)所使用的物理資源(如:cpu,memory,IO等等);
1、安裝
yum install libcgroup -y
2、配置
cat > /etc/cgconfig.conf <<END
mount {
cpuset = /cgroup/cpu_and_mem;
memory = /cgroup/cpu_and_mem; //cpuset memory資源子系統掛載路徑
}
group chunk_server { //控制族羣chunk_server,可包括lssubsys -a查看到的一些系統支持的子系統
cpuset {
cpuset.cpus = "0,2,4,6"; //cpu使用第0,2,4,6,屬於同一node
cpuset.mems="0"; //node 0的memory資源
}
memory {
memory.limit_in_bytes=4G; //memory限制大小爲4G
memory.memsw.limit_in_bytes=4G; //限制mem+swap的大小爲4G
memory.swappiness=0; //積極使用物理內存(同vm.swappiness)
}
}
group other {
cpuset {
cpuset.cpus = "1,3,5,7";
cpuset.mems="1";
}
memory {
memory.limit_in_bytes=8G;
memory.memsw.limit_in_bytes=8G;
memory.swappiness=0;
}
}
[root@abc tmp]# numactl --show
policy: default //當前numa策略爲default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7
cpubind: 0 1
nodebind: 0 1
membind: 0 1 //以上爲可供綁定的cpu mem node等資源
[root@abc tmp]# numactl --hardware
available: 2 nodes (0-1) //表示有兩個可用節點
node 0 cpus: 0 2 4 6
node 0 size: 8192 MB
node 0 free: 2904 MB //節點0包含的cpu及其內存使用情況(本地資源情況)
node 1 cpus: 1 3 5 7
node 1 size: 8179 MB
node 1 free: 4220 MB //節點1
node distances:
node 0 1
0: 10 20
1: 20 10 //節點0訪問節點0即本地資源的代價是10,節點0訪問節點1的資源代價是20(訪問本地資源比遠程快)
在Linux上NUMA API支持四種內存分配策略:
1. 缺省(default) - 總是在本地節點分配(分配在當前線程運行的節點上)
2. 綁定(bind) - 分配到指定節點上
3. 交織(interleave) - 在所有節點或者指定的節點上交織分配
4. 優先(preferred) - 在指定節點上分配,失敗則在其他節點上分配
綁定和優先的區別是,在指定節點上分配失敗時(如無足夠內存),綁定策略會報告分配失敗,而優先策略會嘗試在其他節點上進行分配。強制使用綁定有可能會導致前期的內存短缺,並引起大量換頁。缺省的策略是更加普適的優先策略。
三、使用cgroup軟件對資源進行分配控制與隔離
Cgroups是control groups的縮寫,是Linux內核提供的一種可以限制、記錄、隔離進程組(process groups)所使用的物理資源(如:cpu,memory,IO等等);
1、安裝
yum install libcgroup -y
2、配置
cat > /etc/cgconfig.conf <<END
mount {
cpuset = /cgroup/cpu_and_mem;
memory = /cgroup/cpu_and_mem; //cpuset memory資源子系統掛載路徑
}
group chunk_server { //控制族羣chunk_server,可包括lssubsys -a查看到的一些系統支持的子系統
cpuset {
cpuset.cpus = "0,2,4,6"; //cpu使用第0,2,4,6,屬於同一node
cpuset.mems="0"; //node 0的memory資源
}
memory {
memory.limit_in_bytes=4G; //memory限制大小爲4G
memory.memsw.limit_in_bytes=4G; //限制mem+swap的大小爲4G
memory.swappiness=0; //積極使用物理內存(同vm.swappiness)
}
}
group other {
cpuset {
cpuset.cpus = "1,3,5,7";
cpuset.mems="1";
}
memory {
memory.limit_in_bytes=8G;
memory.memsw.limit_in_bytes=8G;
memory.swappiness=0;
}
}
END
memory.limit_in_bytes 內存;
memory.memsw.limit_in_bytes 內存與swap的和(大於memory.limit_in_bytes);
cgconfigparser -l /etc/cgconfig.conf 測試配置是否正確;
3、啓動
/etc/init.d/cgconfig restart
4、任務使用
killall -9 chunk_server
cgexec -g memory,cpuset:chunk_server /usr/local/gfs/bin/gfs_chunk_server_daemon.sh
killall -9 vip_cdn
cgexec -g memory,cpuset:other /usr/local/vip_cdn/bin/monitor.sh
以上步驟的2跟4操作方法我覺得比較適用,當然也可以使用命令對資源進行掛載、分配、使用,如:cgcreate/cgget /cgset /cgdelete/cgclear/cgclassify等;
5、某些命令
[root@abc tmp]# lssubsys -am //查看當前支持的子系統及其掛載情況
ns
cpu
cpuacct
devices
freezer
net_cls
blkio
perf_event
net_prio
cpuset,memory /cgroup/cpu_and_mem
[root@abc tmp]# lscgroup //查看當前cgroup層次結構
cpuset,memory:/
cpuset,memory:/other
cpuset,memory:/chunk_server
[root@abc tmp]# wc -l /cgroup/cpu_and_mem/chunk_server/tasks
31 /cgroup/cpu_and_mem/chunk_server/tasks
[root@abc tmp]# wc -l /cgroup/cpu_and_mem/other/tasks
243 /cgroup/cpu_and_mem/other/tasks
//當前這兩個資源group中的任務數,tasks中記錄的是進程id(也可以手動加入某進程id到tasks文件中,則該進程及其子進程將受到該group控制)
[root@abc tmp]# cat /proc/`pidof chunk_server`/cgroup
5、某些命令
[root@abc tmp]# lssubsys -am //查看當前支持的子系統及其掛載情況
ns
cpu
cpuacct
devices
freezer
net_cls
blkio
perf_event
net_prio
cpuset,memory /cgroup/cpu_and_mem
[root@abc tmp]# lscgroup //查看當前cgroup層次結構
cpuset,memory:/
cpuset,memory:/other
cpuset,memory:/chunk_server
[root@abc tmp]# wc -l /cgroup/cpu_and_mem/chunk_server/tasks
31 /cgroup/cpu_and_mem/chunk_server/tasks
[root@abc tmp]# wc -l /cgroup/cpu_and_mem/other/tasks
243 /cgroup/cpu_and_mem/other/tasks
//當前這兩個資源group中的任務數,tasks中記錄的是進程id(也可以手動加入某進程id到tasks文件中,則該進程及其子進程將受到該group控制)
[root@abc tmp]# cat /proc/`pidof chunk_server`/cgroup
2:memory,cpuset:/chunk_server //查看chunk_server程序所在group信息(此處表示層次爲2,資源爲memory和cpuset,group爲/chunk_server)
[root@abc tmp]# numastat //numa的訪問統計(numa未關閉時)
node0 node1
numa_hit 124707339647 29192299625
numa_miss 13468643333 2043118290
numa_foreign 2043118290 13468643333
interleave_hit 10961 10991
local_node 124707158180 29191808808
other_node 13468824800 2043609107
[root@abc tmp]# numastat //numa的訪問統計(numa關閉時)
node0
numa_hit 1201229534
numa_miss 0
numa_foreign 0
interleave_hit 21915
local_node 1201229534
other_node 0
6、自動配置及使用cgroup
上面的1-4是簡單的安裝以及使用cgroup來控制資源分配到程序,如果是批量部署,讓程序啓動的時候自動加入group,而不是手動cgexec呢,可以使用cgred服務配合cgroup自動控制程序及其子進程,下面是針對目前線上大多數機器的部署腳本:
cat cgroup.sh
#!/bin/bash
# bigy @ 20130916
#檢查節點node個數
nodes=`/usr/bin/numactl --hardware |awk '/available/{print $2}'`
if [ $nodes -lt 2 ];then
echo "available nodes is $node,not support"
exit 1
fi
#獲取節點
node0=`/usr/bin/numactl --hardware |awk -F: '/node 0 cpus/{print $2}' |awk '{print $1","$2","$3","$4}'`
node1=`/usr/bin/numactl --hardware |awk -F: '/node 1 cpus/{print $2}' |awk '{print $1","$2","$3","$4}'`
#若機器numa架構,則檢查並cgroup
rpm -qa |grep -q libcgroup || yum install libcgroup -y || (echo "yum install libcgroup error" && exit 1 )
#=====update /etc/cgconfig.conf =====
cat > /etc/cgconfig.conf <<END
mount {
cpuset = /cgroup/cpu_and_mem;
memory = /cgroup/cpu_and_mem;
}
group chunk_server {
cpuset {
cpuset.cpus = "$node0";
cpuset.mems="0";
}
memory {
memory.limit_in_bytes=4G;
memory.memsw.limit_in_bytes=4G;
memory.swappiness=0;
}
}
group other {
cpuset {
cpuset.cpus = "$node1";
cpuset.mems="1";
}
memory {
memory.limit_in_bytes=8G;
memory.memsw.limit_in_bytes=8G;
memory.swappiness=0;
}
}
END
#=====update /etc/cgrules.conf =====
#格式爲: 用戶:程序 子系統 邏輯掛載點
#程序:可以爲程序名稱、程序全路徑(程序須全路徑運行),或者程序的啓動腳本
#掛載點:lscgroup命令查看
#掛載點:lscgroup命令查看
cat > /etc/cgrules.conf <<END
*:/usr/local/gfs/bin/chunk_server cpuset,memory /chunk_server
*:/usr/local/vip_cdn/bin/monitor.sh cpuset,memory /other
END
#===== start cgconfig and cgred =====
/etc/init.d/cgconfig restart
/sbin/chkconfig cgconfig on
/etc/init.d/cgred restart
/sbin/chkconfig cgred on
echo "===== install cgroup done! ====="
*:/usr/local/gfs/bin/chunk_server cpuset,memory /chunk_server
*:/usr/local/vip_cdn/bin/monitor.sh cpuset,memory /other
END
#===== start cgconfig and cgred =====
/etc/init.d/cgconfig restart
/sbin/chkconfig cgconfig on
/etc/init.d/cgred restart
/sbin/chkconfig cgred on
echo "===== install cgroup done! ====="
#重啓程序,讓其自動加入group中
echo "===== kill processes for restart ====="
killall -9 chunk_server
/usr/local/gfs/bin/gfs_chunk_server_daemon.sh
killall -9 vip_cdn
/usr/local/vip_cdn/bin/monitor.sh
說明:
*:/usr/local/gfs/bin/chunk_server cpuset,memory /chunk_server
或者*:chunk_server cpuset,memory /chunk_server
程序啓動必須是全路徑啓動,否則匹配不到;
*:/usr/local/vip_cdn/bin/monitor.sh cpuset,memory /other
由於http_down啓動後是./vip_cdn,不是全路徑運行,所以不能像chunk_server一樣直接寫chunk_server;可以寫全路徑的監控腳本。
7、關閉numa
當系統跑的程序比較多而且資源使用不易控制的時候,可以考慮把numa關閉。對部分機器做了不同的測試,關閉numa的效果稍微好點,目前已經全部在os內核關閉。
關閉方法:
1.硬件層,在BIOS中設置關閉;
2.OS內核,啓動時kernel後添加參數numa=off;
3.可以用numactl命令將內存分配策略修改爲interleave(交叉)。
echo "===== kill processes for restart ====="
killall -9 chunk_server
/usr/local/gfs/bin/gfs_chunk_server_daemon.sh
killall -9 vip_cdn
/usr/local/vip_cdn/bin/monitor.sh
說明:
*:/usr/local/gfs/bin/chunk_server cpuset,memory /chunk_server
或者*:chunk_server cpuset,memory /chunk_server
程序啓動必須是全路徑啓動,否則匹配不到;
*:/usr/local/vip_cdn/bin/monitor.sh cpuset,memory /other
由於http_down啓動後是./vip_cdn,不是全路徑運行,所以不能像chunk_server一樣直接寫chunk_server;可以寫全路徑的監控腳本。
7、關閉numa
當系統跑的程序比較多而且資源使用不易控制的時候,可以考慮把numa關閉。對部分機器做了不同的測試,關閉numa的效果稍微好點,目前已經全部在os內核關閉。
關閉方法:
1.硬件層,在BIOS中設置關閉;
2.OS內核,啓動時kernel後添加參數numa=off;
3.可以用numactl命令將內存分配策略修改爲interleave(交叉)。
ps:
由於線上機器業務比較複雜,只是大概的分了兩個組來隔離,保證最重要的服務能正常而不受影響即可。我們線上機器部署的複雜性,numa基本關閉也很少使用cgroup做資源隔離。但有個機房比較特殊幾臺24核64Gmem萬兆網卡機器當作一個節點,這樣每個機器上面的程序就更多了,這時使用cgroup對各個程序做了資源隔離,效果很好,由於程序性能問題,目前這幾臺機器只跑了大概15G帶寬的樣子。