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