Cgroup和Namespace在測試中的使用(上)


 

Cgroup和Namespace在測試中的使用(上)

很多時候需要測試程序在資源受限情況下的表現,普通的做法可能是不斷對系統加壓使能夠分配給目標程序的資源變少,換另一個思路思考,可以嘗試限制分配給目標程序的資源總數,使得機器狀態健康的情況下讓程序資源使用達到飽和。

作為一個正在做着容器項目的人,知道容器技術是依靠Cgroup和Namespace來實現的。在容器中,cpu和內存資源是使用Cgroup來控制,PID、IPC、網絡等資源是通過Namespace來划分。在程序沒有部署在容器的情況下,我們仍可以利用Cgoup和Namespace來構造場景完成一些異常測試,如利用Cgroup的資源控制功能做資源滿載的測試;利用Namespace的資源隔離特性做一些網絡異常測試而不影響其他程序的運行。

Cgroup介紹

Cgroup是進行分組化管理的Linux內核功能,具體的資源管理是通過子系統來完成的。可以理解為子系統就是資源控制器,每種子系統就是一個資源的分配器,比如cpu子系統是控制cpu時間分配的,使用方式如下

安裝(ubuntu)

#apt-get install cgroup-bin

基本命令

cgclassify -- cgclassify命令是用來將運行的任務移動到一個或者多個cgroup。
cgclear -- cgclear 命令是用來刪除層級中的所有cgroup。
cgconfig.conf -- 在cgconfig.conf文件中定義cgroup。
cgconfigparser -- cgconfigparser命令解析cgconfig.conf文件和並掛載層級。
cgcreate -- cgcreate在層級中創建新cgroup。
cgdelete -- cgdelete命令刪除指定的cgroup。
cgexec -- cgexec命令在指定的cgroup中運行任務。
cgget -- cgget命令顯示cgroup參數。
cgred.conf -- cgred.conf是cgred服務的配置文件。
cgrules.conf -- cgrules.conf 包含用來決定何時任務術語某些 cgroup的規則。
cgrulesengd -- cgrulesengd 在 cgroup 中發布任務。
cgset -- cgset 命令為 cgroup 設定參數。
lscgroup -- lscgroup 命令列出層級中的 cgroup。
lssubsys -- lssubsys 命令列出包含指定子系統的層級

子系統說明

可以使用lssubsys -a來列出系統支持多少種子系統,和:比如cpu是控制cpu時間片的,memory是控制內存使用的

#lssubsys - a
cpuset
cpu,cpuacct
memory
devices
freezer
net_cls,net_prio
blkio
perf_event
hugetlb

主要的幾種子系統說明如下:

blkio 這個子系統設置限制每個塊設備的輸入輸出控制。例如:磁盤,光盤以及usb等等。
cpu 這個子系統使用調度程序為cgroup任務提供 cpu的訪問。
cpuacct 產生cgroup任務的 cpu資源報告。
cpuset 如果是多核心的 cpu,這個子系統會為cgroup任務分配單獨的 cpu和內存。
devices 允許或拒絕cgroup任務對設備的訪問。
freezer 暫停和恢復cgroup任務。
memory 設置每個cgroup的內存限制以及產生內存資源報告。
net_cls 標記每個網絡包以供cgroup方便使用。
ns 名稱空間子系統
perf_event: 增加了對每group的監測跟蹤的能力,即可以監測屬於某個特定的group的所有線程以及運行在特定 CPU上的線程

要為Cgroup分配限制的資源,首先要掛載子系統,然后才有控制組,比如想要對目標程序進行內存限制,那就需要掛載memory子系統

使用lssubsys -am來顯示已經掛載的子系統

#lssubsys -am

cpuset /sys/fs /cgroup/cpuset
cpu,cpuacct /sys/fs /cgroup/cpu,cpuacct
memory /sys/fs /cgroup/memory
devices /sys/fs /cgroup/devices
freezer /sys/fs /cgroup/freezer
net_cls,net_prio /sys/fs /cgroup/net_cls,net_prio
blkio /sys/fs /cgroup/blkio
perf_event /sys/fs /cgroup/perf_event
hugetlb /sys/fs /cgroup/hugetlb

可以手動掛載或者卸載子系統,如執行umount /sys/fs/cgroup/memory,memory子系統就被卸載了,這時候手動執行# mount -t cgroup -o memory memory /sys/fs/cgroup/memory就又掛載上了。
要確保需要的子系統都掛上了,不然創建控制組的時候會報錯 is not mounted

#cgcreate -g memory,cpu:/hzmali_test

cgcreate: can't create cgroup /hzmali_test: Cgroup one of the needed subsystems is not mounted

如何創建control group(即需要資源管理的組)呢, 這里用cgcreate命令,當然也有其他方法, 如cgconfig.conf等

#cgcreate - g memory,cpu:/hzmali_test

這里有個重要特性:一個組可以同時做多個資源的限制,如這里我同時限制了memory和cpu,然后memory和cpu子系統目錄下會自動生成這個組的目錄和些文件,如memory

#/sys/fs/cgroup/memory/hzmali_test$ ls -lrt

-rw-r--r-- 1 root root 0 Jul 26 20: 56 tasks
-rw-r--r-- 1 root root 0 Jul 26 20: 56 notify_on_release
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .use_hierarchy
-r--r--r-- 1 root root 0 Jul 26 20: 56 memory .usage_in_bytes
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .swappiness
-r--r--r-- 1 root root 0 Jul 26 20: 56 memory .stat
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .soft_limit_in_bytes
---------- 1 root root 0 Jul 26 20: 56 memory .pressure_level
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .oom_control
-r--r--r-- 1 root root 0 Jul 26 20: 56 memory .numa_stat
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .move_charge_at_immigrate
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .max_usage_in_bytes
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .limit_in_bytes
-r--r--r-- 1 root root 0 Jul 26 20: 56 memory .kmem .usage_in_bytes
-r--r--r-- 1 root root 0 Jul 26 20: 56 memory .kmem .tcp .usage_in_bytes
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .kmem .tcp .max_usage_in_bytes
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .kmem .tcp .limit_in_bytes
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .kmem .tcp .failcnt
-r--r--r-- 1 root root 0 Jul 26 20: 56 memory .kmem .slabinfo
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .kmem .max_usage_in_bytes
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .kmem .limit_in_bytes
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .kmem .failcnt
--w------- 1 root root 0 Jul 26 20: 56 memory .force_empty
-rw-r--r-- 1 root root 0 Jul 26 20: 56 memory .failcnt
-rw-r--r-- 1 root root 0 Jul 26 20: 56 cgroup .procs
--w--w--w- 1 root root 0 Jul 26 20: 56 cgroup .event_control
-rw-r--r-- 1 root root 0 Jul 26 20: 56 cgroup.clone_children

文件很多,選幾個重要的講下:

  • tasks 可以將想要限制資源的進程都加到這個文件中
  • memory.max_usage_in_bytes內存的最大使用量,用來限制資源
    -memory.soft_limit_in_bytes 和 memory.limit_in_bytes 的差異是,這個限制並不會阻止進程使用超過限額的內存,只是在系統內存不足時,會優先回收超過限額的進程占用的內存,使之向限定值靠攏。
  • memory.oom_control
    包含一個標志(0或1)來開啟或者關閉cgroup的OOM killer。如果開啟(1),任務如果嘗試申請內存超過允許,就會被系統OOM killer終止。OOM killer在每個使用cgroup內存子系統中都是默認開啟的。如果需要關閉,則可以向memory.oom_control文件寫入1:

# echo 1 > /sys/fs/cgroup/memory.oom_control
如果OOM killer關閉,那么進程嘗試申請的內存超過允許,那么它就會被暫停,直到額外的內存被釋放

  • memory.mem.usage_in_bytes 當前進程內存用量,因為現在還沒有進程加到組里,就是0了
  • memory.mem.failcnt顯示內存達到限制值的次數

Cgroup文檔

Cgroup的使用細節,子系統和參數設置都可以可以在https://www.kernel.org/doc/Documentation/cgroups/中找到,繼承等特性由於篇幅所限,可以看下文檔

Cgroup實戰

內存限制測試

用控制組限制目標程序內存使用為1000000 byte,當然,需要root執行
echo "1000000" >memory.limit_in_bytes

一般更推薦用cgset來設置數值

cgset -r memory.limit_ in_bytes= 1000000 hzmali_ test

然后構造一個吃內存的程序,每運行一次內存使用就大幅增加

#vim memtest.sh

x= "hahaha"
while [ True ]; do
x= $x $x $x $x $x $x $x $x $x $x
sleep 1
done;

然后運行程序,並將進程pid寫入mem下面控制組的tasks中

#./memtest.sh &
[ 1] 17638
# echo 17638 > /sys/fs/cgroup/memory/hzmali_test/tasks

使用cgclassify 可以將運行中的進程加到task中,如果控制組有多個資源的控制,使用命令會比echo方便很多

cgclassify -g mem:hzmali_ test 17638

然后這貨就在不斷占內存,由於沒有設置disable oom killing,所以最后會oom被kill掉

# cat /sys/fs/cgroup/ memory/hzmali_test/ memory.usage_in_bytes
966656
# cat /sys/fs/cgroup/ memory/hzmali_test/ memory.usage_in_bytes
978944
# cat /sys/fs/cgroup/ memory/hzmali_test/ memory.usage_in_bytes
995328
#
[1]+ Killed ./memtest. sh

CPU限制測試

我的機器上有2個核

%Cpu0 : 0.0 us, 0.3 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

寫個死循環腳本cpu_test.sh跑一下

x=a
while [ True ]; do
x= $x
done;

如果我不想把機器跑死,這里想要限制組里的進程的CPU使用,有2種做法
1.在cpu子系統中控制cpu調度的配額
先看下當前cpu分配情況

cat /sys/fs /cgroup/cpu /hzmali_test/cpu.cfs_quota_us
- 1
cat /sys/fs /cgroup/cpu /hzmali_test/cpu.cfs_period_us
100000

-1表示無限制,這里改為50000,即相對於cpu.cfs_period_us 來說為50000/100000約占1個核50%的cpu時間

#./cpu_test.sh &
[ 1] 17709
# echo 17709 >/sys/fs/cgroup/cpu/hzmali_test/tasks

或者直接使用命令cgexec執行

cgexec - g cpu:hzmali_test ./cpu_test. sh

top了下基本上就是在50%的cpu占用

%Cpu0 : 50.5 us, 0.0 sy, 0.0 ni, 49.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.0 us, 0.3 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
PID USER PR NI VIRT RES SHR S % CPU %MEM TIME+ COMMAND 17709 root 20 0 25368 2020 1764 R 50.2 0.1 1: 14.74 bash

2.在cpuset控制物理cpu的分配
當前使用了上面的方法后,我們發現進程的CPU使用都在Cpu0上,這次希望只用Cpu1來跑這個小程序
所以把控制組也加到cpuset

# cgcreate -g cpuset:/hzmali_test

看一下現在使用的cpu的設置

# cat /sys/fs /cgroup/cpuset /hzmali_test/cpuset.cpus
0- 1

改為只用Cpu1,輸入以下命令

# echo 1 > /sys/fs /cgroup/cpuset /hzmali_test/cpuset.cpus
# echo 17709 > /sys/fs /cgroup/cpuset /hzmali_test/tasks

或用命令

# cgset -r cpuset.cpus='1' hzmali_test
# cgclassify -g cpu,cpuset:hzmali_test 17709

top一下,內存的使用從CPU0到CPU1了

%Cpu0 : 0.0 us, 0.0 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
%Cpu1 : 50.3 us, 0.0 sy, 0.0 ni, 49.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

PID USER PR NI VIRT RES SHR S % CPU %MEM TIME+ COMMAND
17709 root 20 0 25368 2108 2076 R 50.1 0.1 8: 56.78 bash

IO限制測試

用dd對硬盤進行寫操作

# dd if= /dev/sda of= /dev/ null &

打開iotop看下IO速度

Total DISK READ : 100.37 M/s | Total DISK WRITE : 0.00 B/ s
Actual DISK READ: 100.37 M/s | Actual DISK WRITE: 0.00 B/ s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
18081 be/4 root 100.37 M/s 0.00 B/s 0.00 % 1.34 % dd if=/dev/sda of=/dev/null

為了控制IO速度,在blkio上創建控制組

# cgcreate -g blkio:/hzmali_test

查看下硬盤號

# ls -l /dev/sda
brw-rw ---- 1 root disk 8, 0 Jul 25 22:46 /dev/sda

設置硬盤號和對應的讀取速度限制,然后執行同樣的命令

# cgset -r blkio.throttle.read_bps_device="8:0 1000000" hzmali_test
# cgexec -g blkio:hzmali_test "dd if=/dev/sda of=/dev/null"

用iotop查看下,速度果然就降到1M以下

Total DISK READ : 996.55 K /s | Total DISK WRITE : 0.00 B/s
Actual DISK READ: 996.55 K /s | Actual DISK WRITE: 0.00 B/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
18188 be /4 root 996.55 K/s 0.00 B /s 0.00 % 99.99 % dd if=/dev /sda of=/dev/ null

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM