|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 mytomorrow 于 2020-9-8 18:08 编辑 : \+ X7 C4 D+ y1 T9 G
. Z" v$ A9 c, Z# D6 Z' p主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法。. K" g6 T' v4 \
1 c3 J9 s6 d4 _1 a( [
$ l/ g# x% g$ {: J
4 `" m3 D l8 K( dCPU资源控制2 h" p6 i' T: T* Y2 [
每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的.
7 M! W8 |1 N7 ^; O( V4 W, d
. ]8 I3 h- u, O3 z9 d2 {Linux系统中有多种调度策略, 各种调度策略有其适用的场景, 也很难说哪种调度策略是最优的.
7 I1 E5 V+ z, f1 d2 G5 z$ c8 Y7 {( F1 W. E' H& m
Linux的调度策略可以参见代码: include/linux/sched.h3 t( Q, @. ^! H) i) x" W2 `/ v
# d5 e; P4 F1 Q# Z4 c
复制代码& W6 W* K, C5 j8 A9 q# J% V" q% v
/*
9 }' y8 I; y0 e% ~ * Scheduling policies
9 m4 q m% t! b& \* H, { */4 x) n& j& `, c$ s
#define SCHED_NORMAL 0
5 D6 f( W" L: x5 A& B0 p#define SCHED_FIFO 1
. c6 C: ?0 F$ ]3 X#define SCHED_RR 2+ o' M- r) ^( p4 |
#define SCHED_BATCH 3- E P- o) q7 l: Q* N
/* SCHED_ISO: reserved but not implemented yet */5 o, _* {5 p! U! J0 P
#define SCHED_IDLE 5( I: r4 ]* p9 s' b
/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */
$ U4 _3 L* y! w4 T7 w5 q#define SCHED_RESET_ON_FORK 0x40000000
t j8 j, {4 s) ]- {- e2 U复制代码
* i; b5 R- D, G- s* f
# z- f* R; [8 q# e7 |9 c# i" |) a9 P/ |) L% R" T5 P0 a2 `# B9 T
Linux 系统也提供了修改调度策略的命令和系统调用接口.
# N9 e. h- l% p2 \/ G- O: W. B
& p% B- p) P& `6 l+ u: G调用接口请查询相关文档, 这里主要介绍一下修改调度策略的命令 - chrt.
- X- a* m9 _5 v- H' a0 c5 a4 [% V$ b' o7 |
复制代码
' {1 ~% C' l7 j3 y# 在一个终端中执行4 s! \0 U3 q& ~4 b! g
sleep 1000
' A: h* J+ g& L3 y# 打开另一个终端; O; T- K+ L6 n1 q$ d" D- |
ps -ef | grep sleep # 找出 sleep 1000 的pid, 这里假设是 1234$ m' Z z N9 f: G8 ]; g
chrt -p 1234 # 可以查看 pid=1234 的进程的 调度策略, 输入如下:
- W$ o* |7 N& o F* D6 H" H# p4 H) G pid 1234's current scheduling policy: SCHED_OTHER+ N0 o; e) X' `* L% |# \2 L/ r
pid 1234's current scheduling priority: 0
8 Q: C6 {: G( G" ?' i0 A
, b; a# ?. D1 E7 Z& p. v3 [chrt -p -f 10 1234 # 修改调度策略为 SCHED_FIFO, 并且优先级为10$ X" x9 I, n- E8 ?$ Y# Y+ S
chrt -p 1234 # 再次查看调度策略
; E1 M- X5 }8 c pid 1234's current scheduling policy: SCHED_FIFO
, Z* I, N9 \2 h pid 1234's current scheduling priority: 10
3 @, O" u; y0 @复制代码" o/ B( h6 _1 W9 H
~3 c& P+ d1 i2 f5 m
% s. N" U7 s& D) o, E3 R
补充:
# ~6 d$ \7 P u# m/ I
& o; J& B4 f2 }) B( M. ochrt 也可以直接指定一条命令, 并设置这条命令的优先级的调度策略, 具体查看 chrt --help
! F: a* k. [) a& D查看一个进程的调度策略, 除了使用 chrt 命令之外, 还可以 cat /proc/<; PID>/sched& Y8 }* x$ K" ~2 ~ _7 X3 _
8 M" y9 w/ B" ?, e
4 p! s: w$ _- @; k4 w0 A实时进程的CPU控制
4 C" S, Y4 E' ^, s" B& g9 E$ i" O所谓的实时进程, 也就是那些对响应时间要求比较高的进程.6 H X _& L& e1 H4 S. p: P
: K1 |4 n; n2 D9 H4 u( I$ F+ ?. V, f这类进程需要在限定的时间内处理用户的请求, 因此, 在限定的这段时间内, 需要占用所有CPU资源, 并且不能被其它进程打断., `/ S) ]. x' W5 t1 o7 Z5 \! r" G
; w1 r3 G( t/ u) ~9 t在这种情况下, 如果实时进程中出现了类似死循环之类的情况, 就会导致整个系统无响应.% @$ i9 Q% d6 B: C% h8 Q! H0 `! m
, f/ ^6 f. _! q, H. g6 k因为实时进程的CPU优先级高, 并且未处理完之前是不会释放CPU资源的.
8 p5 ~% \4 k- B0 o" ]2 |- V
# u7 S: ]% ]6 y$ t/ S" g
d0 n$ |' y* ] z1 j3 ?+ ^. g r' g x4 D8 T; g- S
所以, 内核中需要有一种方式来限制实时进程的CPU资源占用.
4 @3 O: L9 B0 r( ]3 `. {- X: r
@% C0 v/ h2 p, a; A5 H
$ G$ x6 x& @! t
! W0 S. y9 J& N, t" y4 X; M9 I系统整体设置
0 e0 x6 \! S, S8 e1. 获取当前系统的设置; t- ~# r: ?5 W7 m
4 ]5 X& T' W2 O0 r; @" g! Osysctl -n kernel.sched_rt_period_us # 实时进程调度的单位CPU时间 1 秒
. l: [3 F1 M! O# u' e5 }10000007 E, }3 j( _" m- y
sysctl -n kernel.sched_rt_runtime_us # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒+ V8 K8 Q3 o+ V' v% U
950000
; I5 R9 h& A4 m这个设置说明实时进程在运行时并不是完全占用CPU的, 每1秒中有0.05秒的时间可以给其它进程运行.
$ s4 J( z7 G) P2 a4 w4 s! R* j
5 y1 u T8 g4 f* @这样既不会对实时进程的响应时间造成太大的影响, 也避免了实时进程卡住时导致整个系统无响应.
0 U6 Z1 m0 o1 C9 Y+ f0 K% g
: i d: D; z# Y& l2 c
2 l4 c& O2 f, W2 ~4 @1 d, g+ q
, m$ ^) R) ]# I# Y% a# W3 b2 r" b2. 设置实时进程占用CPU时间2 I6 h5 n4 k3 E! m- }; m2 K
7 y* ~6 e1 _0 A7 o; ~* \& _上面的默认设置中, 实时进程占用 95% 的CPU时间. 如果觉得占用的太多或太少, 都是可以调整的.比如:
! V0 P* u2 n, j+ ]( d3 B t" E; I8 R( @: D
sysctl -w kernel.sched_rt_runtime_us=900000 # 设置实时进程每1秒中只占0.9秒的CPU时间
; ^ P# h0 V- G+ S' Qkernel.sched_rt_runtime_us = 900000
( d) n3 M4 R1 f N0 w1 zsysctl -n kernel.sched_rt_runtime_us
: c+ W4 q& e+ _0 l. i900000' K5 p( S" B4 f6 [/ ~. [1 j
K5 E) S& R, y! D# c
9 V5 \6 l5 F+ C* l: `7 ecgroup 中的设置
$ c) b; x: W' J1 I/ S* T整体设置是针对整个系统的, 我们也可以通过 cgroup 来对一组进程的CPU资源进行控制.8 t1 ]% d3 l. Q) V( _
+ E2 U, ]4 S! L m# W
如果想在 cgroup 中对 sched_rt_period_us 和 sched_rt_runtime_us 进行控制, 需要内核编译选项 CONFIG_RT_GROUP_SCHED=y
! S2 V' h! X/ D" ?
9 Y7 l3 e, ~ s5 D# K3 I. d; p! k- y查看当前系统的内核编译选项方法如下: (debian 7.6 系统)! `0 O8 e" u9 _; _
4 a, t* y4 w8 L" { V2 wcat /boot/config-`uname -r`5 T; y7 T: Z; V# ~
查看 CONFIG_RT_GROUP_SCHED 是否启用
' _3 u" x' S* `% @
7 H9 ^/ X( G" @% ^cat /boot/config-`uname -r` | grep -i rt_group
0 g& s/ k' O. i: ]! z8 r2 v# CONFIG_RT_GROUP_SCHED is not set
6 X& D! @/ m1 r$ r: z! B8 ?6 M9 ~( gdebian 7.6 默认没有启动这个选项, 所以挂载cgroup之后, 没有设置 sched_rt_period_us 和 sched_rt_runtime_us 的文件/ W1 l! z% |3 @; C* @5 C2 F
9 n- M: c. g( t# s- Y
复制代码3 {. Q6 j0 p/ l: u* e- u
mkdir /mnt/cgroup$ h9 p7 j: p* U4 W& `* \% N( R
mount -t cgroup cgroup /mnt/cgroup/
3 n8 q; u( H- tcd /mnt/cgroup/
3 O) V( h5 C% I# O2 K5 G% j z7 K5 Xls -l5 {/ J: G! ]: g$ Q3 x
total 0) i6 a. ?1 E2 O- Y
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_merged- u4 W5 ~# Z n& h- L( `
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_queued4 ]: B6 I& n' \* f# {2 R* C2 [% H
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_bytes
6 J: O* X' i b H+ I-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_serviced
: h+ L8 k( V4 O8 Z" P-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_time2 `8 K* [! _% l9 h3 |- Y0 q. [
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_wait_time v* S- L7 y. Z/ f* p% F* [8 J0 `
--w------- 1 root root 0 Aug 28 09:06 blkio.reset_stats
|! t d6 J% p. {6 G6 H5 X-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.sectors
8 t" u% }$ Y5 Q6 E- g9 H! w-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.time* K* a- L4 t* p* m8 s0 c
-rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight+ L% Z3 ]/ i% u! m2 C
-rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight_device
$ k1 Y- w+ H! h: u2 Z7 ^/ V+ C-rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.clone_children
! L/ x8 O6 \5 ~ M--w--w--w- 1 root root 0 Aug 28 09:06 cgroup.event_control; I3 K) W" P0 }! |
-rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.procs
; N* `9 O# q& ?5 o7 X-r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.stat
; q) V0 ]! I# k-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage
5 _4 W" b% ~: l-r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage_percpu
, P4 H7 p5 O ^+ N) L-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpu_exclusive
: m+ T4 n1 p4 l7 T7 q-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpus
b; }1 |% U# Y; b-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_exclusive+ x P- v& x+ @
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_hardwall
5 l9 g: O) c& P" v8 ?; X. s-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_migrate% H* q7 z q9 Z b
-r--r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure" t0 J4 `1 m! I9 `" ~0 a
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure_enabled# ^* k' Z8 g! ?
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_page3 n7 }. _$ A3 {. p8 J8 @
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_slab& {8 ?3 e- Z. |0 U
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mems* }4 d) L0 X" Z q) n% A) t. ~
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_load_balance
* L; r4 S' f9 J' T( `" A* I-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_relax_domain_level
0 B* r& b( c- n; v3 O: P-rw-r--r-- 1 root root 0 Aug 28 09:06 cpu.shares5 U0 x# J2 I' [! Z7 n$ _9 V2 x, }$ R, F q
--w------- 1 root root 0 Aug 28 09:06 devices.allow6 c1 X/ f" U s; b3 M
--w------- 1 root root 0 Aug 28 09:06 devices.deny" g; O& M5 i: s1 q
-r--r--r-- 1 root root 0 Aug 28 09:06 devices.list
( H! T, d# s9 \, \( P-rw-r--r-- 1 root root 0 Aug 28 09:06 net_cls.classid5 B" C% B+ O$ S" v1 d
-rw-r--r-- 1 root root 0 Aug 28 09:06 notify_on_release) Q5 P F! Y3 m5 c
-rw-r--r-- 1 root root 0 Aug 28 09:06 release_agent
" T2 K- G7 l8 {; ]% ]-rw-r--r-- 1 root root 0 Aug 28 09:06 tasks
7 N' z1 Q1 T) @/ f! ^% a; N0 u* M( S复制代码
. J: Z, q" s3 Z# y# ?
- d+ E; z, z$ w1 j7 v0 m" [# o" X; r5 C; w+ D- x; A5 k
果然, 只有cpu.share, 没有 cpu.sched_rt_period_us 和 cpu.sched_rt_runtime_us; H& c2 M# Q/ O5 x' f
+ k# _1 ~' b/ W没办法, 重新编译内核, 编译内核的具体方法参见: 编译Linux内核7 l9 N. E# l3 a* `
6 C9 P* M' {2 y/ {% j" A6 d- J( e, X
为了节约时间, 我们用 make localmodconfig 来创建 .config 文件, 然后修改其中的 CONFIG_RT_GROUP_SCHED=y, O, Y7 d1 ] Z E6 M9 G7 K
Z! u3 A& D5 [/ P7 N下载源码等等参见: 编译Linux内核, 主要步骤如下:
1 ^8 j: C- X2 M2 S" r1 H
: A) |: b+ `; x8 ^$ D3 E2 y8 z复制代码% `' q& R1 t! q6 Y# @; g
cd /path/to/linux-source-3.2
' ~7 y. S4 P, U0 zmake localmodconfig
' q0 P1 Q( m1 U! Dvim .config # 设置 CONFIG_RT_GROUP_SCHED=y 并保存
& \5 l j' u" xmake
. q r+ M" Z7 N6 S bmake modules_install& j9 ^$ j" r5 r. W/ G& t% i. q. l
make install
! x8 i5 Z" f# oreboot # 重启之前看看 /boot/grub/grub.cfg 中, 默认启动的是不是新安装的内核: r# X1 V" `6 e3 w
复制代码
4 P$ U: f) e2 C4 P& ^" }
9 B' r' Y' Z/ _1 x u% ]启动到新内核, 再次查看内核选项 CONFIG_RT_GROUP_SCHED 是否启用
" q: E9 n4 \7 ^2 h. M* c: h
r" Q# V% |( ?/ i$ u2 Vcat /boot/config-`uname -r` | grep -i rt_group) f3 m* D$ f! T u' q$ l$ G
CONFIG_RT_GROUP_SCHED=y # 已启用
* o* T4 ]# ^4 c5 z. l 9 t5 R9 i. e- ^. U# f I1 x8 p
7 r( O2 ]# s& Z r6 e) ]# [- b$ w
再次挂载 cgroup 文件系统, 发现多了2个配置文件, cpu.rt_period_us 和 cpu.rt_runtime_us, [, R6 M- f# Y6 y4 B s
. A8 g% `: W* C: ^, [
复制代码
7 U1 N1 I& \0 h3 H, vmount -t cgroup cgroup /mnt/cgroup/
2 m- a2 Y+ A; Z; G% _cd /mnt/cgroup/
7 ~6 ^# w6 |2 `7 els -l
- w0 ?+ J9 }' @" x4 itotal 0
, [0 E- j$ }) [. D" c-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_merged" X3 n; G& S9 t( A5 [
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_queued
# z5 _' x7 g6 i! L" B-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_bytes; w- b) I# R0 b3 K0 z$ b4 l
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_serviced6 C- U# N- n, d1 R2 }
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_time
( G" w6 C4 ?! K9 P) d& f-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_wait_time
( I8 _9 t! O6 b& a( ^2 `--w------- 1 root root 0 Aug 28 09:53 blkio.reset_stats: F) e% D @8 p8 {0 X& M f* C2 l
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.sectors
* Y2 t5 _, Q3 p$ l& k5 x-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.time1 E2 [: N* }- O( z u$ {0 k
-rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight. z4 B8 G" I$ w" Z0 e" L7 W& m
-rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight_device
! g3 ^9 ?( H; Z; ?$ j; E8 T-rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.clone_children# z* o4 s; [5 V$ Q
--w--w--w- 1 root root 0 Aug 28 09:53 cgroup.event_control
# }9 z/ H o* a Z3 y2 r9 B-rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.procs- y4 v' q/ [ B" k
-r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.stat
+ {# C3 ^, O4 W3 k* ?-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage
3 j0 k* E# ~7 V5 n# x-r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage_percpu
$ C: D& W# |- m& E9 @-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_period_us4 ]. ~6 @* c f3 E6 C1 S
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_runtime_us
& Z/ B! ]9 l/ ?/ R-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpu_exclusive+ N, n. E* K- g- ^- e
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpus. R* |$ d" }3 H8 L. K/ y
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_exclusive
- V+ ^& v/ J E) b9 _; P-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_hardwall
" C, u; L( N- E+ g% i5 ^$ m-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_migrate8 {1 H8 U: e2 O: E+ c3 H
-r--r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure' {6 g( W5 q4 M2 o" `' c
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure_enabled
( A( @5 t; U5 R2 K$ r-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_page! x$ [& a0 [2 P4 q7 u
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_slab
. m. A. N3 T" B( z-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mems6 S* Z3 v6 g! X* M M5 d6 x( X0 y
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_load_balance
+ z8 G& i# W. q/ f9 E5 G-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_relax_domain_level
6 y5 _, W) }4 K-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.shares: J* W9 v0 A u. r% c
--w------- 1 root root 0 Aug 28 09:53 devices.allow
" k* g4 G) F1 J--w------- 1 root root 0 Aug 28 09:53 devices.deny' E+ j. m8 a7 U J/ \
-r--r--r-- 1 root root 0 Aug 28 09:53 devices.list
" ]/ [: b' g1 W0 \9 L-rw-r--r-- 1 root root 0 Aug 28 09:53 net_cls.classid5 u7 o+ g) ~, }7 o) w5 n Z
-rw-r--r-- 1 root root 0 Aug 28 09:53 notify_on_release
. U+ m9 R9 i5 [& F, E5 I' p-rw-r--r-- 1 root root 0 Aug 28 09:53 release_agent7 c, g1 D: k) Q5 T- e4 N, Q6 |
-rw-r--r-- 1 root root 0 Aug 28 09:53 tasks
- g' k: k1 s, f5 K# N: [: r+ ^( b, G7 g( T
cat cpu.rt_period_us ) j/ ~+ }; ^- {- H$ U
1000000# n4 F% z/ m% L" N+ T" K6 i
cat cpu.rt_runtime_us & ^5 P% X* w s f3 C
950000/ m9 V: Y7 F% R- x2 J+ A
复制代码" ~( @6 }6 p$ h- k
$ |: E1 {1 u2 @. h$ Z
; k! \1 Q; m# f. n+ t! g通过配置 cpu.rt_period_us 和 cpu.rt_runtime_us 就可以对 cgroup 中的进程组中的实时进程进行 CPU使用时间的控制.
( O/ [( S8 ]& E; M
% y! b9 v& B0 O7 W2 u
! o/ t' H, A6 v" ~
7 l0 U2 g+ l$ A( c# [资源控制实例! U) z6 D% j5 p& L! q# B' C# s s
上面主要介绍资源的一些理论基础, 下面通过一些实例演示如果通过 cgroup 来控制进程所使用的 CPU和内存 资源.
i2 n, k! t. J8 l* o
) p1 C% t$ l$ s* S) A% V; h5 ?* XLinux对CPU 和 内存的控制有对应的 cgroup 子系统 cpuset 和 memory
1 u* t1 U9 E1 T$ F
^. L0 j/ u0 T6 T3 M4 T% S( ? : x! z, j) b8 h; ?" v$ A+ p
0 f i# q8 a1 d
实例: cgroup 中对其中 *子cgroup* 的CPU资源控制
8 _1 N$ `* b8 B U8 Y9 s3 t/ I; ~! n对各个 *子cgroup* 的CPU占用率进行控制主要依靠每个 *子cgroup* 的 cpu.shares 文件. C% }% C5 _$ z N
3 E8 R0 s6 w8 ^& A: z5 k2 t$ a; Y直接用实验过程来说话, 其中加入了一些注释.
* a, V1 h% m9 h" J% f2 c* Z$ y/ z: I* ?, d# _' h7 |# C4 @* l7 P% U( p
# 安装需要的软件6 ~6 e3 h% z3 O; f) P- k" I
apt-get install stress # 让CPU达到 100% 的压力工具0 g; C" h# ^8 d1 _
apt-get install sysstat # 查看系统CPU, 内存, 磁盘, 网络等资源使用情况的工具
" R6 c A# u W' W* o. n! V1 c # Z2 R/ H* C8 r, _3 _
! B2 N/ P: M8 F! ~1 t
实例1 - 默认情况, A 和 B 各占CPU总资源的 1/2
% v3 h0 f4 N+ \. l' ?/ E挂载 cgroup 文件系统 (注意加上 -o cpu 的选项)
+ i, @7 L( [9 `2 I% e在 cgroup中创建 2个子cgroup A 和 B2 {* j+ x* j, X+ p0 \$ v! A
默认情况下, cgroup A 和 cgroup B 中的 cpu.shares 中的数值都是 10248 ^6 e! p) X5 e9 V" b
在 A 和 B 中用 stress 工具使其 CPU占用率达到 100%& m, h9 n1 @5 P `
top 命令查看 A 和 B 中进程分别占用的 CPU (应该都是 50%)4 d" g/ }, E9 U
' a2 w0 T# ^9 U+ p8 L, J
0 v0 [1 g3 F& ^" u q3 v复制代码
; ], P. y# T$ P1 G6 j3 l# 挂载 cgroup 文件系统3 W/ O9 k* E9 n3 T
mount -t cgroup -o cpu cgroup /mnt/cgroup/
* W0 G8 h( K" e9 H" n. Ecd /mnt/cgroup
6 H0 l) C2 N, b% Bls -l
; |! S( u6 K6 _9 V5 {* ]total 0
" } M L9 X: D# ~8 I5 I+ H- e-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_merged
& a. H0 e5 [% x1 y# {% {2 p-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_queued o$ a* S- `5 E/ z
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_bytes
) k8 {: b4 z8 Q e-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_serviced2 P4 ^) S+ w% J; S
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_time0 }' Z ?' C7 _
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_wait_time
7 \3 ~9 P: R3 w# }' d: x--w------- 1 root root 0 Aug 28 11:29 blkio.reset_stats
& N$ Y& o; O$ W5 O5 L& u% ~-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.sectors
+ Z, T4 Q; W; j9 e+ F$ h9 Y. x, f7 T-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.time
\4 y8 N! e2 d4 F7 [" N7 y-rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight
+ g4 c" G; k4 t! l" {-rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight_device
1 k5 L* ]9 |$ m-rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.clone_children
/ y# x+ V# A8 ]' _1 U9 W--w--w--w- 1 root root 0 Aug 28 11:29 cgroup.event_control
7 B9 K. ^) v5 K7 G; U4 `-rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.procs K" z h+ g8 @6 [5 w" ~$ h
-r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.stat
5 W% c2 X- ^, P8 _/ ^/ ?& l- H-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage3 p X' F! ^3 i# ]8 s9 D
-r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage_percpu1 E& H0 a9 ]' e
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpu_exclusive
! n% I% H; R$ \$ }6 N( t' P-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpus
# ?) h: I( o9 w5 N7 W( w-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_exclusive
( _6 p& z' S3 }; u6 [7 K7 R-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_hardwall
( |2 \+ _0 g" a/ k2 }% Q; }) k9 `-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_migrate$ Y: \8 Q" f# ~ t$ T6 H
-r--r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure
% d# u& d2 z$ N& e3 O" f2 f-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure_enabled
3 p `2 H: _( d" w-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_page
! M8 r& L- S1 ?' @: w/ {1 @' `-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_slab
. v4 H4 u9 W3 A# I# x v s0 }1 n6 l( R-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mems2 g5 ?8 v) e4 g3 g0 u; X
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_load_balance: Y' b! Y" O2 a
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_relax_domain_level
1 k9 K, k- M% z4 F R* C8 ]-rw-r--r-- 1 root root 0 Aug 28 11:29 cpu.shares& [: r" v E$ O) O) V( d4 G# {
--w------- 1 root root 0 Aug 28 11:29 devices.allow
1 j: V* I& K/ x( j" C1 z0 _--w------- 1 root root 0 Aug 28 11:29 devices.deny' y# x2 Z$ C& _/ w8 O
-r--r--r-- 1 root root 0 Aug 28 11:29 devices.list3 s% E* r1 j/ r0 H
-rw-r--r-- 1 root root 0 Aug 28 11:29 net_cls.classid5 P J, q' X5 w+ ]
-rw-r--r-- 1 root root 0 Aug 28 11:29 notify_on_release! q" z! f% r5 A4 {$ S
-rw-r--r-- 1 root root 0 Aug 28 11:29 release_agent5 [ ]& e4 i7 L8 G6 s3 C7 p
-rw-r--r-- 1 root root 0 Aug 28 11:29 tasks
# ?) z* u# n- z( f8 D; P. V/ A( [$ R1 F+ H. L" p; y
# 创建 子cgroup A 和 B
' l- Q7 q% U4 L3 t/ h0 }' fmkdir {A,B}; w" K$ }6 [( k! y5 t
cat A/cpu.shares
9 A1 m) a; `$ P: k9 b# j+ s2 J1024
# A) ^3 \" n5 Q( {. T5 L6 |$ bcat B/cpu.shares # X: L: z3 i, f$ h( Z6 s
10247 @! r/ ~. } J
% [4 S4 M* ~: Y$ o5 S/ {8 R
# 在 A 和 B 中分别通过 stress 工具使其CPU使用率达到 100%: r; ]# ^9 |7 B. F/ w
echo $$ > A/tasks # 将当前的 SHELL 加入到 cgroup A中4 J2 M) p) l D2 e/ O* g9 p
stress -c 2 # 这里-c 2 是因为测试机器是双核, 要在2个核上都产生 100% 的CPU 占用率
- Z; ` z& E8 Z1 t |# 另外打开一个 shell 窗口, 并将这个shell 加入到 cgroup B中2 @. ?0 t' t: [
echo $$ > B/tasks # 将当前的 SHELL 加入到 cgroup B中# g6 z# K# m6 R4 {
stress -c 2 # 在2个核上都产生 100% 的CPU 占用率! ]5 b" v& {+ V+ t5 [
# 再打开一个 shell 窗口, 用top命令查看 CPU占用情况3 B3 F. ?2 z3 @+ P' K* r
top
. o% W: A( P$ F5 M) T; A0 mtop - 14:10:32 up 43 min, 3 users, load average: 2.31, 1.24, 0.62' r. ~1 n2 A- S9 U: P
Tasks: 78 total, 5 running, 73 sleeping, 0 stopped, 0 zombie1 ]& M7 A: {( U- Z* w
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
- f9 [& D" }1 y+ m1 G6 G& q& }4 MKiB Mem: 1887872 total, 114744 used, 1773128 free, 10472 buffers8 s. X$ e) }) g
KiB Swap: 3982332 total, 0 used, 3982332 free, 45068 cached0 ?# B+ V8 C7 W& v
( h! T5 b2 T& v+ k0 \. j PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
# ?' o. O$ ?* l9 {8 [3350 root 20 0 6524 92 0 R 49.9 0.0 0:08.73 stress
. @. b2 }* h7 B7 a+ @; z& {: o3351 root 20 0 6524 92 0 R 49.9 0.0 0:08.67 stress 0 a5 D5 y, q( _# |
3353 root 20 0 6524 92 0 R 49.9 0.0 0:07.35 stress ; N6 c( i0 S! K" q V
3354 root 20 0 6524 92 0 R 49.9 0.0 0:07.36 stress
: q4 m2 \. }; E
. P$ S$ T1 R- Z0 B# 查看这 4 个stress 进程是否分别属于 A 和 B
5 s# ?1 W" e6 Q- O" a2 Scat /mnt/cgroup/A/tasks
$ }' L( b" F* S& R; W2 E+ G29453 j7 S; c; d2 H3 a3 G0 m
3349
& g0 M6 ?' H) l: |& Y4 A3350 <-- stress 进程
$ v* o( C. E! ^( p: u3351 <-- stress 进程
, p: Y1 ^; B+ v& z7 Qcat /mnt/cgroup/B/tasks 6 i& ]1 e3 g6 `: j
2996
/ e; o- e8 a E8 d, g3352/ ], B J: C8 Z+ P7 v
3353 <-- stress 进程' B) L0 V1 s! E- t- W
3354 <-- stress 进程
* C; {+ {$ l! ~2 u( z复制代码& g) z4 ~6 C! M; ~- P
可以看出, A和B组中的 2个stress 进程的CPU使用率相加都是 100%,
9 \- A; t r7 @9 u8 D8 Y9 ?; ]! Q4 x+ a* ^
由于我测试的电脑是双核, top所看到的CPU最大使用率是 200%, 所以和预期一致, A和B组各占CPU总资源的 1/25 p% U% e! `( C& R7 n+ X
! B! j/ z/ M+ }9 c* z, g& E
( ?( o: J% U8 @1 W
5 `0 y: F! o7 U实例2 - A group 占用整体CPU资源的 2/3, B group 占用整体CPU资源的 1/3( |9 j' C* r, i$ o2 i9 V( ?# h' V" D
环境同 实例1, 不再重新挂载 cgroup 文件系统, 也不在重建 A 和 B
& h6 j% X$ ?# d8 M# w" XA group 的 cpu.shares 文件不变, 值为 1024
! L4 i$ P# G; J9 _B group 的 cpu.shares 文件中的值改为 512, 这样, 相当于B占用CPU总资源的 1/3 (因为 512 / (512+1024) = 1/3)
7 Y# {3 z- p- n' K! {' q( O4 g, ^同实例1, 通过2个shell窗口, 分别是 A 和 B 的CPU使用率达到 100%, 然后通过 top 查看CPU使用情况
! B9 W4 a+ d) i; W
6 s0 a: p' k- t9 E
# [0 l( D3 ^% B; @7 ^$ J复制代码/ ?! _! I1 W7 t4 _. a3 s$ u3 B
# 在 B 中shell 窗口执行以下命令
6 Q3 h6 w6 R/ O! kcat B/cpu.shares
" G0 o, K$ [* d7 N/ o5 ^1024: z: R* r5 I. d* q
echo 512 > B/cpu.shares / o8 P |" t6 }3 O# G; O
cat B/cpu.shares
6 `) |+ ^$ }4 \4 R9 n3 F2 y6 ]! [512' s p; n7 E: l2 s% T& a5 `
stress -c 2
. K% b# L4 B) P4 a
. P! l) h6 X9 a8 t$ L# 在 A 中 shell 窗口执行以下命令
7 h, E2 l. J- Q" T( n$ v! ystress -c 2
( S# l0 Q4 T `
' n2 Y, [0 Z1 A$ W- u) i# 在第3个 shell 窗口, 也就是 非A, 非B 的那个 shell 窗口, 用 top 查看cpu使用情况
/ s; M3 t- C/ Gtop2 r }' k- u( P+ [4 _( e; s! G) R
top - 14:13:18 up 46 min, 3 users, load average: 2.24, 1.92, 1.01
9 n6 L; r& H, @" h8 M' r7 R# |Tasks: 78 total, 5 running, 73 sleeping, 0 stopped, 0 zombie
* a& E# h7 u8 l* t%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st+ ?+ }9 } ]5 [4 Z
KiB Mem: 1887872 total, 114744 used, 1773128 free, 10488 buffers
3 w" ?% e; O- j2 \$ g" y/ N, G* K/ \KiB Swap: 3982332 total, 0 used, 3982332 free, 45068 cached
6 q: i, j! N7 P& x2 Q; g
; Z( G- k& }% o$ F4 _2 D PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
: y* A1 B# e" \! p+ B! e* U2 d3376 root 20 0 6524 88 0 R 66.6 0.0 0:06.29 stress
2 z( }/ G# r- H2 l1 q8 U' [3377 root 20 0 6524 88 0 R 66.6 0.0 0:06.30 stress
8 H2 ~% g# S4 ?3373 root 20 0 6524 88 0 R 33.3 0.0 0:04.33 stress . D* F% z% O& g. b) }; q
3374 root 20 0 6524 88 0 R 33.3 0.0 0:04.32 stress
/ o) D% U1 g1 o6 d1 o4 E1 }" `" z0 [3 [7 h7 M
# 查看这 4 个stress 进程是否分别属于 A 和 B
) q, }% R/ U7 ?$ h8 x; ucat /mnt/cgroup/A/tasks
" K+ a, p; K3 [7 B& P0 X1 ?+ F; @) N8 z; F2945
6 q* S( \$ P, F! Z/ Q9 W7 b; x( O3375
/ a2 g! n7 L8 l0 }3376 <-- stress 进程) O4 {+ H6 A) ~% v
3377 <-- stress 进程7 l& v5 P( B- }7 `; [4 D0 z
cat /mnt/cgroup/B/tasks 3 [! f* _% F! Y, [
2996
. {% v( v: D* q/ F% ~$ R3372- X7 {5 A; I& u7 A/ u) S, y
3373 <-- stress 进程
5 i$ w9 d. l, y9 Q3374 <-- stress 进程
; e; q5 y3 Q# ?) W; h3 p4 ]: Y复制代码
% A# v, H9 U& H. L& g很明显, A 组中的2个进程占用了CPU总量的 2/3 左右, B组中的2个进程占用了CPU总量的 1/3 左右.
w- n C: A8 Q+ e- e0 y, ?2 \2 E: O9 m4 _1 g0 z
: d3 o1 d4 T/ x& S- s9 c
$ b" s! y: j4 B实例3 - 物理CPU的控制
3 H. @2 a7 E% U$ J上面的实例中, 虽然能够控制每个组的CPU的总体占用率, 但是不能控制某个组的进程固定在某个物理CPU上运行.
2 X; n6 I3 ~# u6 I$ w
3 b# @ b2 |' k; N要想将 cgroup 绑定到某个固定的CPU上, 需要使用 cpuset 子系统.
7 K* q2 Z. O6 j* N$ R2 ^
; B# g8 E5 ?% C) C首先, 查看系统是否支持 cpuset 子系统, 也就是看内核编译选项 CONFIG_CPUSETS 是否设为y
; L- O9 d) r; p; w
1 w+ c4 z) K8 a+ y( w$ t7 D% Bcat /boot/config-`uname -r` | grep -i cpusets
; ?: S/ u5 R) z/ {! ZCONFIG_CPUSETS=y! F! `' c/ s! r7 [- x, _( d
我的测试系统是支持的, 如果你的系统不支持, 就需要重新编译内核了.......
; h& X& A4 O2 p, X4 \! d4 Z: i
" f, w1 |. k1 j9 k
& h* l3 `2 r: w/ ]1 x% ?# Q% d' C7 c& @! l
然后, 用下面的例子演示将 A 和 B中的 stress 都指定到1个CPU上后的情况/ }5 j' |4 `. O; ~% S) J
! J7 |2 g! \$ q4 u$ m5 \卸载当前的 cgroup
% c0 v- D% c7 {* W- m再次挂载 cgroup 文件系统, 并指定 -o cpuset
0 d3 ~; {9 D' I _% t$ L3 K指定 A 的物理CPU为 0 (双核CPU的每个核编号分别是 CPU0, CPU1): n2 B* f5 g f j) T
指定 B 的物理CPU也为 0) O( g+ S9 v* p! _
重复 实例1 中的步骤, 观察发生的变化
- B; n8 d- o2 C$ m# u& U: m 1 h! Z5 p1 v% ?' G) R- N6 G6 ]- H4 J) Q
- i j# o9 @( F( l* F3 q
复制代码- J9 I8 n0 x7 r G8 h* o! `
umount /mnt/cgroup
" y! ]# z; V7 \mount -t cgroup -o cpuset cgroup /mnt/cgroup/
7 @# K6 ?- Y; ]$ u3 @# Xcd /mnt/cgroup
1 S) Q+ L, P5 b7 P3 \% |; jls -l) d5 G, _4 v3 ?7 n: H
total 0
) ]2 O0 Z) S0 Q5 b-rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.clone_children
' m+ d& h" ^3 J5 R# o--w--w--w- 1 root root 0 Aug 28 14:39 cgroup.event_control
) E% j# @% O5 F$ I% _/ t-rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.procs( c5 \' O; n. ?1 B
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpu_exclusive
0 L9 f$ E0 B* ?# S1 u-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpus <-- 这个就是设置关联物理CPU的文件! @% T* O/ x8 N
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_exclusive! g. ^, t" Z K) w) i) P
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_hardwall# f6 s6 ^5 C! x- a/ E9 j
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_migrate
, f5 H; E* _* {-r--r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure2 _$ o* k% l3 c/ h$ g) t5 `
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure_enabled
& t1 `5 j, z$ @' d-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_page
6 |/ L% I2 A( X( C$ A' g-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_slab
1 J# b& g# G# C-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mems
1 ]# e5 i& s+ {-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_load_balance7 w( ]8 t' E; [' H0 B
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_relax_domain_level3 M3 H6 ?" ]: h2 R0 f7 o8 c
-rw-r--r-- 1 root root 0 Aug 28 14:39 notify_on_release
# }# T \& F6 u2 s+ W! l-rw-r--r-- 1 root root 0 Aug 28 14:39 release_agent
6 A0 W" O; G! H/ v, `, t6 e$ h g-rw-r--r-- 1 root root 0 Aug 28 14:39 tasks2 |, f4 T% \6 L" M, c% a
; ~3 q, ?7 u( Q7 {. ^# 创建子cgroup A 和 B
3 o+ }5 g: z" R0 rmkdir {A,B}
% K+ V) o( `4 j& {9 ?! e8 ]cat A/cpuset.cpus % F* m0 n8 U& a; }+ s
<-- 默认是空的+ G+ S! [! ~! {1 K
echo 0 > A/cpuset.cpus
, z0 B/ C! I5 _( o; `0 ncat A/cpuset.cpus
* w0 B4 `2 Y) H6 D; a: J% K0
7 R, C }5 T1 }" qecho 0 > B/cpuset.cpus # 同样, 设置B组也绑定到CPU0% s8 J8 J- N9 B
# 当前Shell加入到 A组 T; F, i/ B0 x! z- |! G
echo $$ > /mnt/cgroup/A/tasks 0 q8 k, O2 y' h! I) a1 b4 U
-bash: echo: write error: No space left on device# l% ~1 h! z& u+ s
复制代码4 h! z) q; b4 l8 m, v" L6 J
! I0 i& a" K( O9 E! }) o* `% v$ R8 r
如果出现上述错误, 只需要再设置 /mnt/cgroup/A/cpuset.mems 即可. (参考: http://serverfault.com/questions/579555/cgroup-no-space-left-on-device)
1 y- k* X" A7 @- D
& Y. s# A; l+ S9 k; i( L# w复制代码 f1 Y2 E1 x% t- J0 M0 {, ]. \
# 同时设置 A 的 cpuset.cpus 和 cpuset.mems
; K: m4 l R G) Kecho 0 > A/cpuset.cpus5 D3 F) l! J. Y$ w" @
echo 0 > A/cpuset.mems- @2 q5 Z' T, u
# B组也同样设置
- h( S1 X6 ?+ E1 [" X0 q- ~echo 0 > B/cpuset.cpus
9 f/ {* e. D" {1 d" D' l9 n' E% oecho 0 > B/cpuset.mems
1 {. l& i% l( U9 B
" v3 q% ]. z; ~! {; E9 U% e1 V# 将当前 shell 加入到 A组+ _- F( v; r" K p/ ]* m$ _* ~
echo $$ > /mnt/cgroup/A/tasks <-- 设置过 cpuset.mems 后, 就没有出错了( ?$ f4 a. Q, L- q
stress -c 2; c4 |$ v, ^1 O& N7 n
- g( a2 L3 ?7 `& N& H. X
# 再打开一个Shell窗口, 并加入到 B组( `4 d5 L0 o) N" q i8 X
echo $$ > /mnt/cgroup/B/tasks
- I3 C b; W6 o8 i; \stress -c 2
& p( j! a" U' B! X8 p8 d( j* b/ j# H
# 再打开第3个 shell 窗口, 用top命令查看CPU使用情况/ f1 w o; ]8 Q
top
. F1 q1 a1 B+ @+ }5 Itop - 15:13:29 up 1:46, 3 users, load average: 1.01, 0.24, 0.12; x, J% C! H2 H/ c% w
Tasks: 78 total, 5 running, 73 sleeping, 0 stopped, 0 zombie, B! a' ^" b/ v7 e) p
%Cpu(s): 50.0 us, 0.0 sy, 0.0 ni, 50.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st4 B; c% M4 o+ C* q( v
KiB Mem: 1887872 total, 117216 used, 1770656 free, 11144 buffers
# }, B) ~ e: hKiB Swap: 3982332 total, 0 used, 3982332 free, 47088 cached9 }8 Q' w O4 G. n
( g- `. K( S( M/ U5 h. q0 I E% y3 X PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND ! f' U1 T) E9 y1 u" L+ y; l! `
3830 root 20 0 6524 92 0 R 25.0 0.0 0:04.96 stress + ]& U4 s4 I ~! I6 r0 X5 F) p5 t
3831 root 20 0 6524 92 0 R 25.0 0.0 0:04.97 stress 6 }6 @5 S7 S5 ]/ a6 p& y+ ^
3834 root 20 0 6524 92 0 R 25.0 0.0 0:03.56 stress
, q+ G6 _6 c' z5 g2 Q3833 root 20 0 6524 92 0 R 24.6 0.0 0:03.56 stress& ^9 W, w6 J2 c3 ]2 E4 O
复制代码
, Y4 } m& w9 `' v) g从上面的结果可以看出, 虽然 stress 命令指定了 -c 2(意思是在2个CPU上运行), 但是由于A和B都只绑定了CPU0,
0 H- i7 V0 B% a& n) \& o, N9 e$ H5 s0 `- G( \2 n; a. c7 y
所以虽然是双核的机器, 它们所占用的CPU总量却只有 100%, 而不是实例1 中的 200%.
" g. P2 p/ o" j, `- J
1 \9 t; w9 r% \ ) i5 I, W) ? Q Y$ m- ~
6 i' E w. A: W) s. S5 Z- z9 a7 j" ^" y如果将B组的物理CPU绑定到CPU1, 那么应该所有 stress 的进程都占用 50%, CPU资源的总量变为 200%.$ Y* r* A8 J2 m- b" H- q: p
7 t9 S* A |8 z) L7 `6 }下面将B组的物理CPU绑定为CPU1, 看看结果是否和我们的预期一样.
4 {- _! Z+ `# M5 H1 m: S; @( V. n- N" n
复制代码
2 M# R+ |7 b# B! s/ i0 X. P# 在 B组的 shell 窗口中执行以下命令: D( m( k2 Q; g8 p& D( t5 Q4 U) n
echo 1 > /mnt/cgroup/B/cpuset.cpus
% G( N5 v: X) r' R% z% Y9 k: vcat /mnt/cgroup/B/cpuset.cpus
% k& U: j9 |5 b6 r1: ~9 v+ a( C* o; N9 ?4 r, y
stress -c 2; t; x" e" `6 Y: g. K* n
1 T9 T+ J' ]0 s" _# 在 A组的 shell 窗口中执行以下命令/ ~( Z' u9 u4 P% s, S* ?' n- z
stress -c 2! S* s9 ^" m: w6 O* w, B
6 C3 X p. x9 B5 ^# 在第3个shell窗口中用top命令查看执行结果6 c/ o3 d8 `9 J
top
1 J( W: T: H' {% e* F4 btop - 15:20:07 up 1:53, 3 users, load average: 0.38, 0.83, 0.56
; p2 ~5 D1 J* @7 NTasks: 78 total, 5 running, 73 sleeping, 0 stopped, 0 zombie! z% y. s. U4 r4 k
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st ~+ ?/ r/ a- d
KiB Mem: 1887872 total, 117340 used, 1770532 free, 11168 buffers6 y! P9 T2 M. O" b7 r
KiB Swap: 3982332 total, 0 used, 3982332 free, 47088 cached$ \; P6 e3 U! d' l j. o
, K& C/ J) j4 O3 L3 X
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
: L1 r% _* ]7 f' b7 z; _ 3854 root 20 0 6524 88 0 R 49.9 0.0 0:03.76 stress
; h9 [: Z: n( W+ x+ ? 3857 root 20 0 6524 92 0 R 49.9 0.0 0:02.29 stress
$ F% Z5 M# M6 \/ l 3858 root 20 0 6524 92 0 R 49.9 0.0 0:02.29 stress
0 B, y+ a+ \: L1 | 3855 root 20 0 6524 88 0 R 49.6 0.0 0:03.76 stress; `* C' v. h) F; F- q6 T' I
复制代码( F# q: q; S3 Q9 u
果然, 和预期一致. A组中的 stress 和 B组中的 stress 在各自的物理CPU上都占用了 100% 左右的CPU使用率.7 [0 k& ]7 A; g' a2 j# L9 A
: l- ~7 }/ v. H$ P2 ^ - ~+ X) G4 \1 t8 j9 M) R
8 G* T9 f, v: R# x+ m5 J5 ?实例4 - cgroup 对使用的内存的控制
( c5 p1 r4 u0 l( D. k2 Y& C- ucgroup 对内存的控制也很简单, 只要挂载cgroup时, 指定 -o memory
8 U$ \6 {: ^3 M6 z# }# Q3 p; e0 d, e/ q' q! H
# 首先之前挂载的 cpuset 子系统
$ @& N* ~4 O2 Z6 _- A3 w( jumount /mnt/cgroup- ?' b2 Y9 Q# Q# b; q: N3 s
5 v2 {) J9 u/ M: O# 挂载cgroup 文件系统, 指定 -o memeory
0 Y9 {2 w/ R5 H0 Z* e0 Amount -o memory -t cgroup mEMCg /mnt/cgroup/
& F4 W6 S6 R3 b) O2 P) V9 c3 `mount: special device memcg does not exist0 N$ u, h6 [0 Q& n) W& m& q% e
. z; \" L& X( Q3 \: u8 m4 E$ n- U+ x; {7 h
出现以上错误的原因可能是因为debian系统中, 默认没有启动 cgroup 的memory子系统. 可以通过以下方法确认:3 e4 i/ @2 |* T3 ?
7 \1 M. Y) y" k0 J2 {6 L* \5 \/ g
复制代码
2 e( G9 o! z# u" X% |/ ocat /proc/cgroups
. u& t1 ^* F% n2 r: ~* u5 J6 X#subsys_name hierarchy num_cgroups enabled
! V& N$ m2 C d, {cpuset 0 1 1
+ e/ M3 Q" u4 k7 m/ c+ \" Tcpu 0 1 16 z' F* a3 T$ Y" Q0 o
cpuacct 0 1 1
' A2 b: b& c' e ?6 L5 O) v' mmemory 1 1 0 <-- 这里的 enabled 是 07 G$ z6 U: P: ^ K) n; E
devices 0 1 1
, N/ Y% ` z3 j6 k5 m7 @+ w9 Ofreezer 0 1 1
# Z/ ?8 @; [ x& d1 t' r* H% ?net_cls 0 1 1/ ?; h) @, j- r! H/ p* V
blkio 0 1 1/ Y; k+ w7 m) a# C; a# t4 h
peRF_event 0 1 1' `! O6 W3 k" x/ C. N& M# E7 J
复制代码
$ R5 {/ }9 b* R& k$ q! }
B# x) r8 y; v
2 ~9 {" L3 w# t3 g为了默认启用memory子系统, 可以设置 grub选项
* A) N% A% J8 N0 Z9 `- [) _/ R% i9 K' x8 W; f. m1 ` K J- a
vim /etc/default/grub
/ T) u8 w; p5 @0 V* y T# 修改 GRUB_CMDLINE_LINUX="" ==> GRUB_CMDLINE_LINUX="cgroup_enable=memory" L0 l8 \9 M4 D8 t% J
# 保存后, 更新grub.cfg3 ~9 e* o# O1 s5 G* ~# @
update-grub* c9 M8 Q$ v0 M, G
reboot; A% a: `$ C( j d0 e* u% |
6 C6 d5 g ]0 d; |' p% q; [( N' \; m- z& ~9 r( a! h
重启之后, 发现 /proc/cgroups 中的memory已经 enabled, 并且也可以挂载 memcg了
8 o3 r! D. q% g: { i; I
5 T7 Y+ V9 v2 o7 |0 m* r$ h; N复制代码
+ t w% C3 r* r# u* Rcat /proc/cgroups
) L% y6 F k1 ]- |4 A% I+ }#subsys_name hierarchy num_cgroups enabled
+ r8 ~& W8 o2 wcpuset 0 1 1
( z. b) S& v/ T! W2 b/ M$ U, ncpu 0 1 1, I5 {) @" J2 K$ E" u' Z
cpuacct 0 1 1, v' z: y1 A1 m9 b' I
memory 1 1 1
7 l, e4 }6 n7 s7 x1 F: W' b" u% Rdevices 0 1 1
3 w, i. b3 G# I1 Q3 n4 Xfreezer 0 1 1
2 a M$ ~' z" R nnet_cls 0 1 1' L, X K8 y) W7 V9 }2 c, D
blkio 0 1 1
; c% R a }# I9 J7 P. ~8 vperf_event 0 1 1
, s; }5 x s- s3 `/ n% _" b4 R- D. B' d
; ?: e3 I3 G9 d# 挂载cgroup 的memory子系统
9 Q! u( h" [( _mount -t cgroup -o memory memcg /mnt/cgroup: {2 [7 r( Y. j( h" ]- N6 z, s
ls -l /mnt/cgroup/ <-- 可以看到有很多 memory 相关的配置
6 X, d, H1 v9 U |1 S' {9 ltotal 0
) l' n! F& t _# b-rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.clone_children9 J: q9 M$ C( c1 {- N6 R4 v
--w--w--w- 1 root root 0 Aug 28 15:54 cgroup.event_control: z/ M3 C. R% K
-rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.procs+ A$ H5 o. i& i& x" C3 ^$ M6 L4 D) Y
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.failcnt
# f2 @: c. J( o0 o) { W) i! n--w------- 1 root root 0 Aug 28 15:54 memory.force_empty3 u/ k9 P9 ~. {( u4 [& n9 V
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.limit_in_bytes <-- 限制内存使用的配置文件
) N$ }+ L& {9 |0 P( W. U; i-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.max_usage_in_bytes8 t4 U1 z- G) A4 X6 Y
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.move_charge_at_immigrate8 T6 i/ R+ B8 P: r$ p, k) P, {
-r--r--r-- 1 root root 0 Aug 28 15:54 memory.numa_stat8 W4 V, g! E& o: Q6 } Y- m( B
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.oom_control) x) A- W# E3 @! O6 I
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.soft_limit_in_bytes+ V: `% ?! Z$ f/ s# }+ s1 @
-r--r--r-- 1 root root 0 Aug 28 15:54 memory.stat8 Y3 A$ u7 M! c0 ?% s7 D
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.swappiness. C' _ I& z, ^0 m% z1 S: W
-r--r--r-- 1 root root 0 Aug 28 15:54 memory.usage_in_bytes
# A2 s- X0 z; H8 Q) d4 r/ G! p# v-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.use_hierarchy
; l) \# S9 E% C-rw-r--r-- 1 root root 0 Aug 28 15:54 notify_on_release4 V6 o; W3 V6 C
-rw-r--r-- 1 root root 0 Aug 28 15:54 release_agent
9 e' W! t9 P% e8 Q) z-rw-r--r-- 1 root root 0 Aug 28 15:54 tasks4 M) ?0 y8 y. j* b" C
复制代码
, T9 f0 d- y% b, D ^ 9 H/ y& L9 O0 B- J( p7 O$ x; m
8 M% j* a4 ^/ S5 V7 ]; I
开始实验:
0 j( W$ c: s* _ O, n- t# i0 N' I3 @( p0 u% T( F
重启系统 (为了保证内存的干净): D* @3 w; m. C
挂载 memcg
. u5 s: B- p D' p4 Y+ r在挂载的 /mnt/cgroup 中创建 组A7 t+ V5 Z+ f7 W- K, a3 Y1 S
将当前shell 加入到 组A( k2 d7 }( a0 Q d1 ^# y
不限制组A的内存, 压缩内核源码包, 并观察压缩前后内存的变化
- ~* d0 i; _, Q3 A重复步骤 1 ~ 4
8 Z) l3 Y9 X( N7 |! |5 k. y7 e限制组A的内存为 10MB, 再次压缩内核源码包, 并观察压缩前后内存的变化- {& N5 {* B5 u1 v( m
# z6 n& J z4 d4 F# M/ Y0 I+ A& z1 |
复制代码: C- k$ E# m$ [" E
# 重启系统* A" a/ l& D& _4 S
reboot$ O" _8 Y: |8 {4 A
0 q( V) Y/ R2 \
# 挂载 memcg
5 c0 F* e/ P) fmount -t cgroup -o memory memcg /mnt/cgroup
# ?% q! x: x2 c1 V/ `; ]- ]1 W) ]' e' U( }9 L
# 创建 组A
1 W: O5 | T8 ]) w- ~7 u$ Pmkdir /mnt/cgroup/A
+ I2 ]. k- j; L {6 R* P9 d1 q' |4 |
2 _. w2 _* C: R0 e# 将当前 shell 加入到组A
& Q+ t! B- D; e' \. u9 N7 xecho $$ > /mnt/cgroup/A/tasks. g$ `1 Z5 c$ R
2 |! F+ m1 ]* ^. a4 H6 K7 V
# 测试不限制内存时, 内存的使用情况, 这里不用linux源码也可以, 但最好用个大点的文件夹来压缩, 以便更容易看出内存的变化.
1 N# ?- G Z7 T y: hfree -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;/ ~' a" P2 a: a* L; _" l/ A
total used free shared buffers cached
7 y5 `0 f- `2 S# F- U! o& t0 UMem: 1843 122 1721 0 9 43
* ^2 A( y9 l( b* X4 a* `-/+ buffers/cache: 68 1774
: q% |) p4 @. H8 j/ @0 E5 N% U1 X0 BSwap: 3888 0 38889 g( f% X: o0 N) j: y) U
total used free shared buffers cached
( J& ~3 n6 @9 x9 o* X2 o9 a3 iMem: 1843 1744 99 0 26 1614
4 e. [6 O- F: u* c-/+ buffers/cache: 104 1739
+ p8 w Q& z4 j5 ]8 KSwap: 3888 0 3888
2 a' @, {' v4 @/ n
+ Y2 k+ D! [3 T; J# A# 重启系统
2 f% y$ v4 B7 ?0 m$ @4 v) O$ \reboot5 [: w" s d6 t3 v ]2 t; G
# |* H. U: h% I
# 挂载 memcg# [: _' \+ b/ } _
mount -t cgroup -o memory memcg /mnt/cgroup# N. y4 Q& H2 U( O( c8 G* h1 D
! M, Z3 l a2 ~# 创建 组A
, R/ r4 @7 Z5 Q. c9 Y' H/ t) G% a. Lmkdir /mnt/cgroup/A7 W+ o/ s- V5 J5 T
8 ~4 ^% v9 }' R$ Y; a0 o
# 将当前 shell 加入到组A* b# O. `. ?2 A8 G! g1 _
echo $$ > /mnt/cgroup/A/tasks9 f* o- @! \0 v0 Z' W0 }
A! k6 F+ Y" O$ O0 O% v0 l# 限制 组A 的内存使用量最大为 10MB
' H7 `8 I; K# J! kecho 10M > /mnt/cgroup/A/memory.limit_in_bytes
# ?# N1 V; ?- q# r/ Q9 w: x) t0 F) f7 [5 f
# 测试限制内存为 10MB 时, 内存的使用情况.
7 H! O0 E' x0 Y5 w2 g2 J5 P# k1 Hrm -rf linux-source-3.2.tar.gz
0 r+ g1 Y4 c# P: dfree -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;" u" }3 J0 z8 X) B
total used free shared buffers cached7 @8 b( L* n8 r. t- f
Mem: 1843 122 1721 0 10 436 {' Q" W$ s" w. U' T$ u$ K
-/+ buffers/cache: 68 1774
; a/ U1 M0 |+ w8 ESwap: 3888 0 3888
0 r- K$ E7 d6 G% X; t7 _ T0 Z; K total used free shared buffers cached
4 w! {$ y( c7 w7 h: pMem: 1843 194 1649 0 14 48$ ?$ ^ A( K; E8 n
-/+ buffers/cache: 131 17128 R6 r+ P) w5 }# b* t
Swap: 3888 0 3888
! z1 Z. B5 m- w% E3 N. l- E复制代码) a% L) \4 I8 m, U. K' v2 y
从上面的结果可以看出限制内存是起了作用的.- T9 Q2 o7 R d) @. E1 q! d
; h0 `* _$ K' b. q! }9 o# W# z# t
不限制内存时, tar 压缩前后 buffer + cache 内存从 (9MB + 43MB) ==> (26MB + 1614MB) 增大了 1588MB
1 t" Q' R M' B+ v0 `9 k" F2 p4 V5 B! J: o& G# q
限制内存后, tar 压缩前后 buffer + cache 内存从 (10MB + 43MB) ==> (14MB + 48MB) 增大了 9MB3 | O; T- W4 H R. J+ n
" h0 ^9 }) z3 F! U% G% o
5 Y6 O) F2 [' I8 V2 R# o6 J+ e0 N4 {2 j1 V7 H
总结* g: X3 e& {. J2 m5 {" r
简单的实验就发现 cgroup 如此强大的控制能力(而且配置也很简单), 这也就难怪LXC等容器技术能如此强大, 如此流行., e* ~) j# S$ ~( P s0 A
$ @1 @7 |) s, h8 ^cgroup 的配置文件很多, 上面的实例中只简单使用了其中的几个配置文件, 如果想深入了解 cgroup, 更好的利用cgroup的话,
3 ]' ^) G4 E, n5 \! g# r
- U' Z' {& _7 J: F' h" Z还得找个介绍cgroup配置文件的文档来研究一下, 这篇博客提供的内容还远远不够. |
|