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 zCPU资源控制( \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& iLinux的调度策略可以参见代码: include/linux/sched.h9 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        56 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     0x400000008 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 HLinux 系统也提供了修改调度策略的命令和系统调用接口.
7 Z' ^: X& g# l# A5 N, `) k4 k3 b) e) p& t  r4 o) G; l
调用接口请查询相关文档, 这里主要介绍一下修改调度策略的命令 - chrt.
% w% V; Y( I% o* N9 z2 h$ D4 p" W; ~3 q
复制代码0 h# J& o7 c0 x% z
# 在一个终端中执行
  a7 |' V+ h' \% S4 Usleep 1000
9 f: b! Z# h# `# 打开另一个终端
# {( [# O, \* Z+ t4 W- g, v7 Vps -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 b0 C) D5 u( \  f: a
chrt -p -f 10 1234   # 修改调度策略为 SCHED_FIFO, 并且优先级为10
- Y* _" a1 `- Echrt -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+ J4 {5 l$ g* N6 d3 ?0 k
补充:
/ I4 X" j& T1 Y2 T) M  H
! ^' N; @( i4 uchrt 也可以直接指定一条命令, 并设置这条命令的优先级的调度策略, 具体查看 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 Q6 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! X1. 获取当前系统的设置
/ 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' Vsysctl -n kernel.sched_rt_runtime_us  # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒( w+ `7 q4 Y4 x' I
9500009 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! S0 R& j) j: ~( i2 j: Q- R: r9 w7 M
/ O. D4 J3 s  _% ]9 [

- [/ m: @& Y2 p; O) M2. 设置实时进程占用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+ rsysctl -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- ?  msysctl -n kernel.sched_rt_runtime_us
4 X1 m6 L0 W; E0 o9 Y$ [9000005 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=y5 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- n9 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* jdebian 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.sectors6 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_device6 a6 C: k" T, k2 E- M- H4 i3 q6 H
-rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.clone_children7 C9 t8 L( B1 j% x0 {% \& M5 Q
--w--w--w- 1 root root 0 Aug 28 09:06 cgroup.event_control9 @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_exclusive2 m+ r* g  _( t' \
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_hardwall1 D1 B' s+ \8 F) ^
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_migrate2 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 tasks2 O) p' ~5 H/ q5 _* e" c& I! x
复制代码
3 D% m0 p8 E# m8 R
3 V- k2 z, V7 t/ s4 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 }+ Ccd /path/to/linux-source-3.2+ e8 ~; L' x# W. s. }+ U
make localmodconfig5 I" k4 r" B. V" r
vim .config   # 设置 CONFIG_RT_GROUP_SCHED=y 并保存
% C3 @0 q. P3 }* n" d% Tmake
/ p7 N/ w' B  r) @make modules_install; i1 ~4 V. _+ i) _
make install
& t' i& Y1 ~$ E5 G/ Vreboot      # 重启之前看看 /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; bCONFIG_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 Lmount -t cgroup cgroup /mnt/cgroup/
; m" }( L8 p% A! v/ \! F* fcd /mnt/cgroup/- O4 e3 h& L* k: Y, `
ls -l
& x/ Y+ E7 ?' b( i3 Ctotal 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.sectors2 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.weight1 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_children3 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.cpus1 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_pressure6 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_balance8 t6 e" D! ^7 K" H( X5 L
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_relax_domain_level8 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.allow3 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.classid1 V% }* X0 S" I5 I. @3 v& v4 `( J3 D
-rw-r--r-- 1 root root 0 Aug 28 09:53 notify_on_release0 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 _) Gcat 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 和 B5 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 ?" |$ Vtop 命令查看 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& smount -t cgroup -o cpu cgroup /mnt/cgroup/
* t2 R! g! c3 C$ c' ocd /mnt/cgroup) z# D) _& b" S6 L7 e2 T
ls -l
" K+ e1 S/ x* |+ Dtotal 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_bytes2 ^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_stats3 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.time8 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_balance4 }. p% B; s4 R* C
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_relax_domain_level9 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.allow6 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.list2 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_agent3 _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* N1024
0 f  \/ W* v1 L& Ocat B/cpu.shares
) C9 ~3 {1 u& P( Z# ^5 a2 `6 o0 W0 ?10246 @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, Mecho $$ > B/tasks  # 将当前的 SHELL 加入到 cgroup B中
# ]9 @9 q, ?/ Z2 x4 f  Wstress -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+ Htop - 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 zombie9 ?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# uKiB 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* B8 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  N3350 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 K3353 root      20   0  6524   92    0 R  49.9  0.0   0:07.35 stress                                                                                                                       
6 q. h5 ~: p1 f7 |4 B3354 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 Scat /mnt/cgroup/A/tasks 7 A! Z  [9 ?2 Z- _& H0 G7 ~( L- f
2945
* h2 u0 q' A0 b8 i) P* n3349
2 o3 t/ |: K( o9 L" @9 P- S3350   <-- stress 进程# S- D9 `  ^3 m
3351   <-- stress 进程
8 ~4 n3 p: v! y5 A8 Dcat /mnt/cgroup/B/tasks 1 f5 S" j( `  ]% X2 \& k
29966 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 和 B1 Q; k% h! Z8 H& s
A group 的 cpu.shares 文件不变, 值为 1024
0 p+ a* g8 G& p- pB 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/ {  A1024
) r' |- F7 A( n1 hecho 512 > B/cpu.shares
+ C* u0 i& X- b  a* ~3 L: K5 ^% Ycat B/cpu.shares 8 @5 A; }* R* v9 M$ W- G8 ~; I
5123 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 Atop
6 j  W' u$ U9 R4 F' ctop - 14:13:18 up 46 min,  3 users,  load average: 2.24, 1.92, 1.01
) f& Q' q0 |. @  v) cTasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie7 `' ^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 G3373 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- vcat /mnt/cgroup/A/tasks
0 d  i( [5 b4 s; Z29455 D( o  D3 i4 ~
3375
4 M* S0 n* o' [6 {8 m6 L5 {. Z5 a7 ?3376    <-- stress 进程
" f* {9 l  M9 v0 n7 T3377    <-- stress 进程
% a5 N: ]+ E( o4 {cat /mnt/cgroup/B/tasks
. g# r, k; g2 ]* r2996/ O  z0 t  I. O
33725 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# wCONFIG_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 cpuset6 @. 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) Oumount /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.procs3 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_hardwall6 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_enabled8 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.mems2 @- ]& 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 tasks3 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.cpus5 D; }8 P4 u& c2 M: u* q- F; }
cat A/cpuset.cpus # A0 L2 x. G8 `0 v
05 s/ _7 M! J. h7 E& h$ u9 `4 e
echo 0 > B/cpuset.cpus   # 同样, 设置B组也绑定到CPU05 k# I' L) P4 _' q9 h9 \
# 当前Shell加入到 A组
$ h% s. M1 I6 H% K) p' S% p8 hecho $$ > /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  }& Eecho 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, Hecho 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  Wecho $$ > /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# kecho $$ > /mnt/cgroup/B/tasks
8 E$ N& _" p% }" v; _stress -c 21 g( ^+ i5 L- G; N/ W
0 v; r/ v/ t5 W! p0 U
# 再打开第3个 shell 窗口, 用top命令查看CPU使用情况
/ Z' V0 I8 w) }& F; D3 Ctop
$ `( b) L* Q! k: y1 t# f+ A+ ytop - 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" bKiB Mem:   1887872 total,   117216 used,  1770656 free,    11144 buffers
! |  b' [! }, r4 G) VKiB 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 E3831 root      20   0  6524   92    0 R  25.0  0.0   0:04.97 stress                                                                                                                       
, E2 y. X( C& [+ w  T3834 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- f4 `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: scat /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.563 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 st5 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 cached4 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 bcpu    0    1    1
5 K3 M  P/ u/ g. A( Y* ccpuacct    0    1    1" N9 t6 J8 ^/ z
memory    1    1    0              <-- 这里的 enabled 是 0
7 q: p) ^% z  bdevices    0    1    1, F0 u( `* x- C
freezer    0    1    1
* X: E' Z7 i1 F, O: k8 A5 Anet_cls    0    1    1
1 ~% k) B9 P' I: \- H, J' Kblkio    0    1    1
  G9 n% H! C3 [+ Z" B& W9 L, operf_event    0    1    16 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/ hvim /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 {) `% `: hupdate-grub
& _: J: s& I; s% yreboot
: 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% Ncat /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' ]  pcpuacct    0    1    1
2 T* s+ _% ?2 t( A6 i, Bmemory    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% Qnet_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 02 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.swappiness3 ?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) Gmount -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/A0 s/ G5 ?+ V7 {& d/ D' ]; N

* I  ~% N! x% e4 H1 S, G$ l# 将当前 shell 加入到组A
0 v. h# e* t& s% necho $$ > /mnt/cgroup/A/tasks
2 B: \% n- g' K" _; X6 E+ q; f7 R- e$ V' Y5 ?5 F
# 测试不限制内存时, 内存的使用情况, 这里不用linux源码也可以, 但最好用个大点的文件夹来压缩, 以便更容易看出内存的变化.
* a' C: A* K% ?8 w  Sfree -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       17747 d* ~7 S1 A# S7 z
Swap:         3888          0       38885 \( y- m; }$ j/ ]2 p" n
             total       used       free     shared    buffers     cached
" z, i) N! T7 D+ T' i( OMem:          1843       1744         99          0         26       16144 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 jreboot0 K% o  r  V- ]+ F/ Q4 _( p. Z
: z9 o: [' e' T; [, v  D
# 挂载 memcg
* |- t; s- I, R( C- M4 A" Fmount -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- fecho $$ > /mnt/cgroup/A/tasks  k' w+ x  S4 R  {) n

" i; }3 R: ~2 l1 |3 S. J# 限制 组A 的内存使用量最大为 10MB7 y5 M1 }) R- U! h5 U6 z
echo 10M > /mnt/cgroup/A/memory.limit_in_bytes4 E* `# s5 a) F  ?, D2 h

# {( Y/ ?6 F- y, V6 X# 测试限制内存为 10MB 时, 内存的使用情况.
1 ~, Y6 n, v- b2 J" T' orm -rf linux-source-3.2.tar.gz2 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! gSwap:         3888          0       38887 X; k6 X7 U8 L  R& p) O
             total       used       free     shared    buffers     cached
0 A5 o" ^7 b: F/ R# NMem:          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 Ucgroup 的配置文件很多, 上面的实例中只简单使用了其中的几个配置文件, 如果想深入了解 cgroup, 更好的利用cgroup的话,
$ w+ Y7 g) E% j% q; Q4 }- I! E9 G5 \3 [2 w  }( g& X0 A
还得找个介绍cgroup配置文件的文档来研究一下, 这篇博客提供的内容还远远不够.
作者: CCxiaom    时间: 2020-9-8 19:01
CPU和内存




欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/) Powered by Discuz! X3.2