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