我們環境使用的Linux內核版本是4.4,已支持cgroup,只要在內核配置中選上cgroup,並勾選自己想要的配置(general setup->control group support->)
網上有各種資料介紹cgroup,這里我就不詳述了,直接mount cgoup
mkdir cgroup
mkdir cgroup/cpu
mkdir cgroup/memory
mount -t cgroup -ocpu cpu cgroup/cpu
mount -t cgroup -omemory memory cgroup/memory > /dev/util 2>&1
mkdir cgroup/cpu/cgroup0
1、限制cpu利用率
通過cfs_period_us和cpu.cfs_quota_us配合實現,cfs_period_us默認值是100ms,代表周期時間是100ms,cpu.cfs_quota_us是進程在100ms周期內所能占用的最大時間,可以設置為95ms,即cpu利用率是95%,注意這個單個cpu的利用率;對於多核系統,如果想設置95%利用率,cpu.cfs_quota_us應該是N*cfs_period_us*95%,N是cpu的核數,通過cat proc/cpuinfo查看(CpuNum=`cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c | awk -F ' ' '{print $1}'`)
#set cpu ratio 98%
cfs_quota_us=`expr $CpuNum \* $cfs_period_us \* 98 / 100`
echo $cfs_quota_us > /cgroup/cpu/cgroup0/cpu.cfs_quota_us
echo $rcSPid > /cgroup/cpu/cgroup0/cgroup.procs
對於運行了實時進程的環境來說,需要根據cpu.rt_period_us設置cpu.rt_runtime_us,cpu.rt_period_us是實時進程的周期時間,默認1s;cpu.rt_runtime_us是在一個周期時間內,實時進程占用的最大時間,默認是0;一開始沒有注意到這個,我們的環境一配置上cgroup,就會異常導致重啟,后來發現是rt_runtime_us為0;可以設置成內核默認值950ms(cat /proc/sys/kernel/sched_rt_runtime_us),或者再cgroup的內核配置中去掉sched_rt項。這樣RT進程就不會被cgroup限制,即cgroup0目錄下沒有cpu.rt_runtime_us這一項
將cpu利用率設置好之后,才可以將需要限制的進程pid加入cgroup.procs;由於我們環境中的進程由rcS中起的,因此只需要將一開始只需要將rcS的pid加入cgroup.procs,后續創建的子進程都會被自動加入到cgroup.procs中(獲取pid rcSPid=`ps -o pid,comm | grep -o "[0-9]*.rcS" | grep -o [0-9]*`)
2、限制memory利用率
為了避免某些進程的bug導致內存泄露,可以使用memory.limit_in_bytes限制cgroup0組中所有進程所能使用的最大內存,單位是字節;由於我們環境中的進程由rcS中起的,因此只需要將一開始只需要將rcS的pid加入cgroup.procs,后續創建的子進程都會被自動加入到cgroup.procs中。我的環境設置memory.limit_in_bytes為MemFree-200M(留下200M給內核使用已足夠)
MemFree=`cat /proc/meminfo | grep 'MemFree' | awk -F ' ' '{print $2}'`
MemRatioKB=`expr $MemFree - 204800`
MemRatio=`expr $MemRatioKB \* 1024`#config memory ratio
mkdir cgroup/memory/cgroup0 > /dev/util 2>&1
echo $MemRatio > /cgroup/memory/cgroup0/memory.limit_in_bytes
進程占用的內存超出設置的閾值,會怎么樣呢?會被kill!!如果你不想被kill,那就要置memory.oom_control為1,這樣在進展占用內存超出閾值時,進程會被加入等待隊列直到有內存分配給他;
#disable kill
echo 1 > cgroup/memory/cgroup0/memory.oom_control
memory目錄下其他項:
cgroup.event_control #用於eventfd的接口
memory.usage_in_bytes #顯示當前已用的內存
memory.limit_in_bytes #設置/顯示當前限制的內存額度
memory.failcnt #顯示內存使用量達到限制值的次數
memory.max_usage_in_bytes #歷史內存最大使用量
memory.soft_limit_in_bytes #設置/顯示當前限制的內存軟額度
memory.stat #顯示當前cgroup的內存使用情況
memory.use_hierarchy #設置/顯示是否將子cgroup的內存使用情況統計到當前cgroup里面
memory.force_empty #觸發系統立即盡可能的回收當前cgroup中可以回收的內存
memory.pressure_level #設置內存壓力的通知事件,配合cgroup.event_control一起使用
memory.swappiness #設置和顯示當前的swappiness
memory.move_charge_at_immigrate #設置當進程移動到其他cgroup中時,它所占用的內存是否也隨着移動過去
memory.oom_control #設置/顯示oom controls相關的配置
memory.numa_stat #顯示numa相關的內存
附上cpu利用率消耗程序和內存消耗程序,也是參考別人的。
1、cpu消耗,入參是創見的進程個數,(一個進程消耗一個cpu核)
int main(int argc, char *argv[]){
pid_t pid;
int i, pn=4;
if(argc==2){
pn=atoi(argv[1]);
}
for(i=0;i<pn;i++){
pid=fork();
if(pid<=0)break;
}
if(pid<0){
printf("fork() error\n");
return -1;
}else if(pid==0){
//sub process works
for(;;);
}else{
//wait for the sub process's termination
wait(NULL);
}
return 0;
}
2、內存消耗
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MB (1024 * 1024 * 1024)
int main(int argc, char *argv[])
{
char *p;
int i = 0;
system("cat /cgroup/cpu/cgroup0/cgroup.procs");
while(1) {
p = (char *)malloc(MB);
memset(p, 0, MB);
printf("%dG memory allocated\n", ++i);
sleep(1);
}
return 0;
}