找回密码
 注册
关于网站域名变更的通知
查看: 260|回复: 1
打印 上一主题 下一主题

Linux资源控制-CPU和内存

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-9-8 18:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
本帖最后由 mytomorrow 于 2020-9-8 18:08 编辑
8 L% n( M- y6 B2 n8 Y% Q. \0 T- G$ n! b) J/ i3 E) q) U
主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法。
* p3 o% P: |: F- ?/ s5 Y& p8 {) I- |0 ]- N6 a* D( \
. M5 W2 Y6 O% g& u. p' M% x
7 b- l0 Q: Q9 p, v6 f8 f6 J" d
CPU资源控制
' Y4 q# p; H8 P; C+ w/ c每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的.
. ?0 @7 v! ]5 l* [
9 `, ]1 m# p3 p; E& A5 {Linux系统中有多种调度策略, 各种调度策略有其适用的场景, 也很难说哪种调度策略是最优的.
6 w$ ^" ?4 U. M- \6 [" g" I8 w/ ^0 B1 [1 }0 k7 x) G0 B
Linux的调度策略可以参见代码: include/linux/sched.h9 K" p) u/ _1 O8 j" ?9 M
/ M$ w, X. l& ~( \, L, v& U! s8 @. h
复制代码& Q* J( p* s3 {# M
/*2 [) Z5 H* o* Z4 K% R1 ~2 l5 ?3 a; t
* Scheduling policies
- ?( e8 t1 M) B$ [& c  l9 a */
7 Q1 A$ D2 z% Q- V: I8 y3 T#define SCHED_NORMAL        0# R0 M0 a5 X, L  D( R. s; X1 B( e
#define SCHED_FIFO        1
! j- o, ?. t$ k) N" Z, u#define SCHED_RR        2  p* ~; `. c2 e8 ?. w
#define SCHED_BATCH        3
( x' W; U+ ?1 X8 @% f/* SCHED_ISO: reserved but not implemented yet */
0 P/ G: X5 d# J" C3 t) Z; A; _#define SCHED_IDLE        5. @: z0 h3 `! b# i* w
/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */
7 ]  @+ J; Z- `9 x" Y5 z#define SCHED_RESET_ON_FORK     0x40000000
5 V6 U5 i5 z$ c$ i' `' }复制代码
5 V% \6 p- {: r- J8 H# h
) i: A/ N' T& M  \3 x# Z" \7 h5 y/ |' k. F' M  U' }& v+ u. E
Linux 系统也提供了修改调度策略的命令和系统调用接口.+ d& ~, T, P! J# n) ?) a

7 m* Y7 j, g# P调用接口请查询相关文档, 这里主要介绍一下修改调度策略的命令 - chrt.2 `4 g/ M! n2 S7 O$ J3 H( @/ l

0 G3 N$ Y7 d3 e! H7 Y$ b复制代码
4 D9 n* l* w, |/ |# 在一个终端中执行
$ `5 e* J. e3 `sleep 1000
, ^+ k2 H* D! ]- A1 {# 打开另一个终端% x( u' R% c) e7 g7 Q! I7 u% j, O
ps -ef | grep sleep  # 找出 sleep 1000 的pid, 这里假设是 1234
! ~* D. G' r3 `( u1 schrt -p 1234         # 可以查看 pid=1234 的进程的 调度策略, 输入如下:/ e' L5 I) s0 H. d4 R
      pid 1234's current scheduling policy: SCHED_OTHER
  u# a6 S% c0 D* l- f5 W/ Q      pid 1234's current scheduling priority: 0
: c# m* [; g" o* z1 D9 a4 R8 Q
/ h+ O* U$ U1 F- h6 m% cchrt -p -f 10 1234   # 修改调度策略为 SCHED_FIFO, 并且优先级为10
4 }! j4 t2 H# q2 V7 W1 ]chrt -p 1234         # 再次查看调度策略
0 }; Q. P2 M6 M; i6 B3 C      pid 1234's current scheduling policy: SCHED_FIFO3 s- v4 y8 }2 J% A' M* y( A! p
      pid 1234's current scheduling priority: 10. I4 n" P8 w) w+ E
复制代码7 i  W, [7 s! i' [% I. W

& z0 |! I# n! {  U
- W+ C7 ^7 Y& \1 ]" H6 B补充:! r7 t- `4 p. K$ A! a, y8 c
) `' E2 k4 ]% a9 Y4 l
chrt 也可以直接指定一条命令, 并设置这条命令的优先级的调度策略, 具体查看 chrt --help+ F% z0 o8 s7 {# b* P: N, ]
查看一个进程的调度策略, 除了使用 chrt 命令之外, 还可以 cat /proc/<; PID>/sched3 Z1 c: B0 Z+ O7 d

6 u1 e! [% V3 _# b% r, F, U( Z9 C- _/ @) a
实时进程的CPU控制  e1 z- s3 o4 o
所谓的实时进程, 也就是那些对响应时间要求比较高的进程.* i. L* L' c9 Y# O/ n

. N' E, g; G$ |3 \  e这类进程需要在限定的时间内处理用户的请求, 因此, 在限定的这段时间内, 需要占用所有CPU资源, 并且不能被其它进程打断.
$ Y/ m' Z) K" Y2 j- {) \* G. ~5 N: Q4 L; L! ?$ `$ l
在这种情况下, 如果实时进程中出现了类似死循环之类的情况, 就会导致整个系统无响应.
0 H9 v6 \% w2 ?
8 w% B$ [$ d. `4 Y, W, i因为实时进程的CPU优先级高, 并且未处理完之前是不会释放CPU资源的.$ ^. r" L1 l. `. n- J

4 `- w% A+ r9 X: F
. F; a3 Q; D- M; i9 S
" |" l1 A9 C8 Y# \7 r' W$ [所以, 内核中需要有一种方式来限制实时进程的CPU资源占用.0 c# C9 [) R2 k

$ u3 P5 r- C* p 2 V# m7 _$ _" V# v
" J* z1 S+ O& z' O2 Y
系统整体设置  f- ?# |! {4 J
1. 获取当前系统的设置
6 x0 [4 q' W. j7 ?( u, Y$ u8 ^* T
sysctl -n kernel.sched_rt_period_us   # 实时进程调度的单位CPU时间 1 秒. U. a+ e$ h$ ?9 b
10000009 t9 q% O/ {! n3 r2 k  a5 s; ]# q5 r
sysctl -n kernel.sched_rt_runtime_us  # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒. d4 A/ D1 l6 [4 g
950000& ~% [3 T! _3 q; b) C; [1 U
这个设置说明实时进程在运行时并不是完全占用CPU的, 每1秒中有0.05秒的时间可以给其它进程运行.8 h+ X# Q  Y: |3 k; k; h
0 y7 R4 z  O. h# u( M, ?
这样既不会对实时进程的响应时间造成太大的影响, 也避免了实时进程卡住时导致整个系统无响应./ q; W( y2 k7 [( `; I
) i( F  }' [0 o. X2 G, Y

5 m6 [: c4 F2 s" ?' ?7 e8 L6 ?, H3 k" s1 e/ E1 p* ?
2. 设置实时进程占用CPU时间
$ W' f* ]3 @) P8 V5 e) t/ w
1 Q, l9 |- F  u0 Y7 F$ a上面的默认设置中, 实时进程占用 95% 的CPU时间. 如果觉得占用的太多或太少, 都是可以调整的.比如:
  i3 n0 }8 D& F9 X9 n6 L  k1 u. K2 ]" a
sysctl -w kernel.sched_rt_runtime_us=900000    # 设置实时进程每1秒中只占0.9秒的CPU时间
# N0 B' D" h# ~kernel.sched_rt_runtime_us = 900000/ f' o( W, z4 T  F
sysctl -n kernel.sched_rt_runtime_us 7 C0 C9 j$ f3 G
900000
* n* z: X: g. f5 F, ?& P! H
5 }% s4 @) W5 v% }$ _' U! o( i  g, c! L4 x8 Y+ r. u
cgroup 中的设置
" t3 T5 T0 q' k1 Y  o0 o" \整体设置是针对整个系统的, 我们也可以通过 cgroup 来对一组进程的CPU资源进行控制.
; O  q2 S/ ^; j$ {( {
9 Q. l0 C! T3 G如果想在 cgroup 中对 sched_rt_period_us 和 sched_rt_runtime_us 进行控制, 需要内核编译选项 CONFIG_RT_GROUP_SCHED=y
8 y4 z( n9 ]2 R" C: J* W6 x% O! Q+ k4 h
查看当前系统的内核编译选项方法如下: (debian 7.6 系统)
% e7 O0 P# C! f% C7 B, v& t. y# G, Q4 O1 B1 g
cat /boot/config-`uname -r`7 ~' a2 S  O0 B" H' F5 x1 S8 \
查看 CONFIG_RT_GROUP_SCHED 是否启用
, L, w6 M7 P( X$ n/ O4 ~# R, F5 e$ m$ `3 b$ K& B
cat /boot/config-`uname -r` | grep -i rt_group4 x0 i0 b/ z) y1 D. U
# CONFIG_RT_GROUP_SCHED is not set: O2 T% ]* D) Z9 y# e& L
debian 7.6 默认没有启动这个选项, 所以挂载cgroup之后, 没有设置 sched_rt_period_us 和 sched_rt_runtime_us 的文件
# @  \% p5 a2 \& O0 r9 l: {" n+ c
1 c: R* y% ^. Y, o# Q3 S9 Z复制代码1 q4 P# {" \5 O3 C9 u
mkdir /mnt/cgroup
4 n% q0 _% e" m8 P) xmount -t cgroup cgroup /mnt/cgroup/
5 X7 k+ }5 H. y4 h& Wcd /mnt/cgroup/
5 m7 z# S6 J* Lls -l
2 s& h* F2 j$ o; `6 _total 0
; _! C' F: a/ d, M6 g) @! S# Y" W-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_merged
% D7 A7 Q- H& l2 C9 R- {-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_queued
  D0 \6 B7 e4 Q2 W# |5 o-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_bytes* _1 j+ M# ]: d; X( b, j% x! u
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_serviced1 @+ T' \. N* T' L5 K, b
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_time; Y' g! g# y( [6 h) C
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_wait_time) D; m0 x, u/ p9 v- m
--w------- 1 root root 0 Aug 28 09:06 blkio.reset_stats
( i. V- c  V( y  S* o2 y1 ~-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.sectors
. \7 l% n4 V1 K) G* e! b3 }6 o( Z& [-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.time
; G2 k/ |1 B0 Z, ^. U2 O1 B* U-rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight
1 V6 n+ q. W; q: g- ~4 O# e& \-rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight_device
5 ]: _% R$ D. b" Z- P) |! X-rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.clone_children
+ L/ d3 m1 u+ W; t+ }9 O--w--w--w- 1 root root 0 Aug 28 09:06 cgroup.event_control4 m" \2 x6 a8 X
-rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.procs' a% t) J1 W, e) ^
-r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.stat
8 B: ^9 k  s# E-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage! T( J8 T# e, F, n
-r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage_percpu
, o/ g& a5 d1 W-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpu_exclusive
& _6 {/ g6 @4 i) G4 F4 E! a& _-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpus. q0 W/ {# k3 z7 k6 P
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_exclusive$ ]% l0 M. T) }; Y, m! |6 W
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_hardwall+ h7 m* p* n8 m
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_migrate
: X, |. [8 C: \, E$ t. g) x-r--r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure( z+ @3 G9 z  g
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure_enabled
* P3 v  H' F' ?! p* [3 Q-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_page
6 O% N& Y/ U) n% ]-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_slab
- `, Q, a3 Y! B. T; v0 H& _0 |-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mems; H8 ~( v4 V$ V; \& |7 X; a
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_load_balance$ {/ I5 ^, b9 K! F2 j6 B4 m
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_relax_domain_level/ J5 i; q" f. ~% C  X7 r
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpu.shares
) e5 v" ]; x* \! A--w------- 1 root root 0 Aug 28 09:06 devices.allow! Q, h0 K# i- W8 D+ Y# f
--w------- 1 root root 0 Aug 28 09:06 devices.deny
0 B# `- L; e, g9 x  \6 }% W-r--r--r-- 1 root root 0 Aug 28 09:06 devices.list* s" j' t) `& p4 t, G  [2 g6 @
-rw-r--r-- 1 root root 0 Aug 28 09:06 net_cls.classid' H& ?" m( h( M' c
-rw-r--r-- 1 root root 0 Aug 28 09:06 notify_on_release+ V7 g$ A% ]+ O* _$ u& H2 ?
-rw-r--r-- 1 root root 0 Aug 28 09:06 release_agent
3 d/ ?, n% d0 j5 U8 v1 N-rw-r--r-- 1 root root 0 Aug 28 09:06 tasks9 f& C6 d; R7 z
复制代码( y& J- R6 r9 ^" ?8 j" S4 W
. [5 C1 {! s' z' Q9 F2 A. K

) V- J0 V+ P9 g果然, 只有cpu.share, 没有 cpu.sched_rt_period_us 和 cpu.sched_rt_runtime_us3 G/ {  b+ Z6 G$ m2 U) H! B

& @6 A3 c' q$ y& X% b/ J, z2 m没办法, 重新编译内核, 编译内核的具体方法参见:  编译Linux内核
# ^7 T7 o0 t1 m9 H1 P3 T/ ~# f
% V4 |& J1 \- K6 ]0 ?9 r为了节约时间, 我们用 make localmodconfig 来创建 .config 文件, 然后修改其中的 CONFIG_RT_GROUP_SCHED=y
* u: ]' v+ O# q$ f. d8 [
% H# ~6 Q" g6 }) `* _3 f5 [7 d0 M下载源码等等参见: 编译Linux内核, 主要步骤如下:
; V$ ]0 K  Q8 D& |5 j. c4 Y8 |3 b6 q: a, ]2 O
复制代码+ p, f8 {! c  S! E7 {, L: t- i
cd /path/to/linux-source-3.2+ ?! p; t9 {% Z, S' U
make localmodconfig+ r6 u9 G6 j7 J' w2 m! Y* y
vim .config   # 设置 CONFIG_RT_GROUP_SCHED=y 并保存
+ Y% {9 W& o) Pmake
3 E5 v1 S7 {3 p, }0 Z- K1 fmake modules_install  }5 _* o8 k- |! t1 c5 y  L
make install
/ d1 m, `0 A5 creboot      # 重启之前看看 /boot/grub/grub.cfg 中, 默认启动的是不是新安装的内核4 t6 W6 j/ ^0 {$ z& ]: _& x
复制代码) w- P6 [0 E6 s$ C4 z6 S

* e: P- L, |; t0 q8 z6 Q* k; H启动到新内核, 再次查看内核选项 CONFIG_RT_GROUP_SCHED 是否启用
  x1 x% O) K5 u
( b: a3 b) M/ s3 X! N; K- s1 Ccat /boot/config-`uname -r` | grep -i rt_group; u$ {9 \. x2 `9 ^* v
CONFIG_RT_GROUP_SCHED=y       # 已启用
2 Q1 H, H6 ^: a) Y' Z/ c4 e% j " {& W2 ?0 ]) b) ^0 K, p

* P' D$ U7 S+ ?再次挂载 cgroup 文件系统, 发现多了2个配置文件, cpu.rt_period_us 和 cpu.rt_runtime_us& j# B8 X: N5 x& v1 S
; W4 f& x! l, G2 J; b4 u
复制代码
6 K: @( \0 k4 A# qmount -t cgroup cgroup /mnt/cgroup/
; s, y  ?- n6 F1 Z: \cd /mnt/cgroup/
  r* }) R* f* f2 {& D1 @( Tls -l! Y  f/ @8 A! v" M0 @
total 02 o2 E) t' j9 A) R  W
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_merged8 |5 k$ |* k; J
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_queued% E% ^7 j# J% N7 F. ^3 o; r% U
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_bytes
& \6 S7 @) s" x  a5 m* ]: c-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_serviced' A$ R7 G$ o* P+ d
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_time
% c$ k/ L# E, `9 n-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_wait_time
2 j; H; \( y! t! T( I4 \--w------- 1 root root 0 Aug 28 09:53 blkio.reset_stats
: D/ D$ w% S. K( {& }-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.sectors
  b5 ?9 i, \6 b, b" {-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.time7 N0 R. ]: _( V4 `& I
-rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight& ~& J0 ]0 q4 v" v) a( g7 n
-rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight_device. n2 A# i- J) f$ i' A
-rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.clone_children
/ A; E& K' I# @2 R--w--w--w- 1 root root 0 Aug 28 09:53 cgroup.event_control5 k5 f3 z$ E' V3 }) o
-rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.procs
2 N& C6 w4 Y/ s9 P7 k# V, T$ O-r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.stat
3 B% z9 q# B) D% K5 d-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage
8 x2 z. J+ Y8 l" }$ g3 B-r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage_percpu( \# l* f# O  U9 {( A, w
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_period_us
/ V; P+ J; O/ o-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_runtime_us+ P( x, h2 ]$ m: p' D
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpu_exclusive" i8 A. x$ N' G$ S0 m
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpus) K: j2 D: C% O+ Y2 h
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_exclusive0 B+ O& {# V9 ^5 \, a8 Y7 B
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_hardwall3 [" t% w& T( I9 o% x
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_migrate
& x& }! }- J- u  d% E, d-r--r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure
- b8 p. o" h5 x9 x; c* C-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure_enabled  A4 ^3 a- S. W5 `7 ^
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_page& p( a/ C8 w" H+ e: o$ x2 j
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_slab
9 t! x( U" B8 o7 t% S8 t-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mems
9 i, O3 E2 Z& I4 |" C-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_load_balance
0 B  w' l& ^/ M" T2 X8 ?# {6 y6 o-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_relax_domain_level
( ?, |8 F( I: E: Q  @. u-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.shares
# ~0 \) m5 \3 O+ T; ]' h--w------- 1 root root 0 Aug 28 09:53 devices.allow# W1 F: L- I$ l3 x, h3 k
--w------- 1 root root 0 Aug 28 09:53 devices.deny' c7 u- G6 B/ ]
-r--r--r-- 1 root root 0 Aug 28 09:53 devices.list  ~% J- a% Y: w  L4 M
-rw-r--r-- 1 root root 0 Aug 28 09:53 net_cls.classid* _6 B7 n0 i- B/ L3 K  u
-rw-r--r-- 1 root root 0 Aug 28 09:53 notify_on_release
- d5 [! d, F3 F; C! ?-rw-r--r-- 1 root root 0 Aug 28 09:53 release_agent' d1 F, ~& H" A3 I
-rw-r--r-- 1 root root 0 Aug 28 09:53 tasks
: q3 f# ^2 s! n5 h8 y
" V2 [- J6 H1 R9 k; \4 @+ S0 P& Gcat cpu.rt_period_us ' w4 `& I7 L: Q5 {8 p& }  d
1000000( H, b0 u5 I, K
cat cpu.rt_runtime_us
) y% q0 a3 y# |( r8 r9500003 a/ i* `- W# @6 k
复制代码& c; ~2 a3 ~' d6 i) i5 j

' p9 t  w  C1 M3 b( J
; _, {+ q$ X# t& K7 u4 `, V8 B通过配置 cpu.rt_period_us 和 cpu.rt_runtime_us 就可以对 cgroup 中的进程组中的实时进程进行 CPU使用时间的控制.
2 v7 \. E; `' C. }1 U( ]5 ~* o5 q$ a: {3 l
8 ?$ e& R$ L8 r/ M1 h, a
$ i; u! x* {- V& j( k5 C
资源控制实例
( Z' o( Z7 H( l8 L上面主要介绍资源的一些理论基础, 下面通过一些实例演示如果通过 cgroup 来控制进程所使用的 CPU和内存 资源.
4 m7 j# K0 U: `- i1 f% `1 z' A/ W4 U8 H! Z- v  _4 c& T$ h
Linux对CPU 和 内存的控制有对应的 cgroup 子系统 cpuset 和 memory4 y! U* H/ f' O) E( u* W7 w" o0 R
0 w8 {. ]+ `7 X

' T  t+ |  R' u  E7 ?; `" N9 h1 L: W, c8 o8 d4 O
实例: cgroup 中对其中 *子cgroup* 的CPU资源控制4 K3 h+ K$ R" s! h, b
对各个 *子cgroup* 的CPU占用率进行控制主要依靠每个 *子cgroup* 的 cpu.shares 文件% r- m3 Y$ c9 d8 A% @- L" j' G
$ |+ o2 k3 R, a0 e1 L% B
直接用实验过程来说话, 其中加入了一些注释.
( L9 d. O, J3 p
% W" B/ g9 x; X. ^# 安装需要的软件
( Z4 G- H. j! S3 U% k; k+ L3 Z4 oapt-get install stress     # 让CPU达到 100% 的压力工具  {- e9 A) L( @2 j* W0 J5 \% M
apt-get install sysstat    # 查看系统CPU, 内存, 磁盘, 网络等资源使用情况的工具
; f* n9 F* H( i $ J! x5 Z4 a8 M" l; m4 D9 g

7 k) N. u4 f8 _* u实例1 - 默认情况, A 和 B 各占CPU总资源的 1/2) f6 ]2 x+ w' b2 q0 v  }% ?# l
挂载 cgroup 文件系统 (注意加上 -o cpu 的选项)  T! v" g) L- U: f6 H- R
在 cgroup中创建 2个子cgroup A 和 B+ `$ t4 }( i! y* _' ~/ k
默认情况下, cgroup A 和 cgroup B 中的 cpu.shares 中的数值都是 1024
. E+ K3 n, ?) e( N: k; R& |# n  s" V在 A 和 B 中用 stress 工具使其 CPU占用率达到 100%/ k& }: T3 X6 B( ^  L: c; M8 ^
top 命令查看 A 和 B 中进程分别占用的 CPU (应该都是 50%)$ c% v! \! m% \. [3 Q
* h* _& t: f; E
: l- i) |" d. q
复制代码
* q) @% i" {" _; ]# 挂载 cgroup 文件系统
% R4 t8 F- G/ n4 z8 Z, Lmount -t cgroup -o cpu cgroup /mnt/cgroup/
# |4 Q  Z* C# [: H% o& R, K$ ^cd /mnt/cgroup. g& w+ s* Q* ]! d
ls -l
  ~. s2 ]1 b2 {3 T/ R8 z9 btotal 0: G9 U  X6 Z$ o/ b# F* x! P
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_merged
2 C% }8 h) D, K( _+ ?  J7 {: C-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_queued, A/ W0 @6 v: u& t
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_bytes
- k- b, s) t( }  _9 U  f-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_serviced3 H/ z/ ]. N' ]) m, |$ y! o6 W) u( p
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_time' g0 z  I/ z3 X* Y- r
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_wait_time& T, v1 v( d& W- m. B
--w------- 1 root root 0 Aug 28 11:29 blkio.reset_stats
0 @2 i8 A/ C  M  W* J; q-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.sectors0 v8 G6 L( E  x* k. B
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.time
  e1 [' R: x; [; s$ D- j-rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight
; |1 B7 k( |8 G. r& l, B, d-rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight_device
! `8 L- `# U& s: [, l& y-rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.clone_children
* B8 f# {! x' f% b" E  g--w--w--w- 1 root root 0 Aug 28 11:29 cgroup.event_control; B6 b# {! b) o1 d4 ^0 v4 O( f
-rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.procs
$ W# {! Z, c, i& ^( [% y( Q-r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.stat
- o# X. V* Q3 T, o& c) x" r-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage
+ w$ u" G$ Y1 R6 f1 B1 z% l-r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage_percpu' ]: e; G& }& m! V7 x: V; i- e
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpu_exclusive
9 ~+ q6 G. K, X9 F( }-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpus4 [6 |8 E: {, K: T- {5 r2 F
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_exclusive
) K" h6 d" p1 ~! W4 ^-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_hardwall2 j& i/ v: M, w1 B- J7 T
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_migrate, }3 ^$ y. z8 h% s( m% f; n8 V" s
-r--r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure, O) e: p" U, X
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure_enabled# g% q. D" Y! N' w* O
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_page: A' {3 j8 [+ s* n$ m3 s2 ~
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_slab2 h' r* J  [  F
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mems' g/ f" \* k8 _; b; A+ s
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_load_balance
6 O* t& f0 m" q" p4 ?; u-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_relax_domain_level
8 v0 S% G) Q. A: H- B# v-rw-r--r-- 1 root root 0 Aug 28 11:29 cpu.shares5 E1 Q- ]( [: b7 f: @( z
--w------- 1 root root 0 Aug 28 11:29 devices.allow" K& y* f+ W5 m7 T  K
--w------- 1 root root 0 Aug 28 11:29 devices.deny
* d; e* O- H6 j; c5 Q( a  ^2 \-r--r--r-- 1 root root 0 Aug 28 11:29 devices.list
1 W6 a) E1 \( o! v1 _- K-rw-r--r-- 1 root root 0 Aug 28 11:29 net_cls.classid
  Z/ v( U/ B+ p-rw-r--r-- 1 root root 0 Aug 28 11:29 notify_on_release: @: Q# R4 D8 q5 l2 g) H
-rw-r--r-- 1 root root 0 Aug 28 11:29 release_agent
3 ], R. Z, F& I- |1 t8 T' u-rw-r--r-- 1 root root 0 Aug 28 11:29 tasks
4 w) b- t% G; ?# L* S
# W/ H7 |/ E6 F1 h9 n( W# 创建 子cgroup A 和 B4 `, `! ?7 t3 s# `
mkdir {A,B}. C. O. b& ?# M& Y
cat A/cpu.shares
4 q4 {! l# k" `3 I1024; H( a% c3 _9 S! j2 N7 g
cat B/cpu.shares
' w* o' N1 s/ U* D10249 f( R7 o" @( l. Z: j8 X

8 V3 ]7 J  L+ d2 s4 J# 在 A 和 B 中分别通过 stress 工具使其CPU使用率达到 100%1 j# Y/ X. w3 t9 U
echo $$ > A/tasks  # 将当前的 SHELL 加入到 cgroup A中# A! G8 S' m8 p2 @  `* T( {) }
stress -c 2    # 这里-c 2 是因为测试机器是双核, 要在2个核上都产生 100% 的CPU 占用率
2 h2 D+ i2 @8 Z& `3 k& Z# 另外打开一个 shell 窗口, 并将这个shell 加入到 cgroup B中, O9 m6 D: ~; G$ t$ m
echo $$ > B/tasks  # 将当前的 SHELL 加入到 cgroup B中
, d/ q. k6 T8 h6 q0 h1 V2 f# R0 jstress -c 2    # 在2个核上都产生 100% 的CPU 占用率
# x' E* @6 Y* P2 b3 H" \% @( i3 ?# 再打开一个 shell 窗口, 用top命令查看 CPU占用情况
& t9 H( G0 Z/ ?8 v5 I: otop5 \# t* q- l# d9 V) j3 ~1 F
top - 14:10:32 up 43 min,  3 users,  load average: 2.31, 1.24, 0.62
* `3 A" N6 X2 y, T7 n- U+ W/ MTasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
8 c# \; l/ l, s/ e%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, U: o% Y3 Y* r- Y
KiB Mem:   1887872 total,   114744 used,  1773128 free,    10472 buffers# f# V4 o! N: N' {. V8 \
KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
, ^( l% ?% m' x6 e; C2 k7 W3 k. C4 M+ T
; X0 l# o  y' b9 [9 g. b, x1 ~7 M2 l PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                        }5 F" p& \1 x' F5 n
3350 root      20   0  6524   92    0 R  49.9  0.0   0:08.73 stress                                                                                                                         U% q) |* W  C
3351 root      20   0  6524   92    0 R  49.9  0.0   0:08.67 stress                                                                                                                       ( A8 _6 [' J' J0 v6 g6 v; u2 G
3353 root      20   0  6524   92    0 R  49.9  0.0   0:07.35 stress                                                                                                                       
" u; `  \$ v& R2 H- a9 z# H0 n3354 root      20   0  6524   92    0 R  49.9  0.0   0:07.36 stress                    $ a% z! U& Z8 g  `+ T8 m

5 ?/ ^: ]7 k5 O# 查看这 4 个stress 进程是否分别属于 A 和 B
& Z6 s" Y* p3 e! I# f5 Kcat /mnt/cgroup/A/tasks ; ~. }7 u4 y% o" s" `
2945
$ {5 v) q. E' U3349
) t2 O( t: o5 K" y0 e8 L3350   <-- stress 进程1 {4 L3 K9 z1 @: n6 f
3351   <-- stress 进程
' H$ V9 l6 n5 d# Jcat /mnt/cgroup/B/tasks & q" G2 R, s* }* \4 `: i, }0 p' z3 C
2996- }' w" l$ P* A/ G, f
3352/ u" V+ `& O/ R, D+ @
3353   <-- stress 进程
8 ]) A3 c& J( [+ q' Y3354   <-- stress 进程: l* i* T8 M0 z: z/ k
复制代码7 y' O; w/ ?7 K8 F$ T3 y
可以看出, A和B组中的 2个stress 进程的CPU使用率相加都是 100%,2 w' `% d- F5 E4 G
/ Z2 h5 j  j( Y' H& p5 @* |9 u3 n
由于我测试的电脑是双核, top所看到的CPU最大使用率是 200%, 所以和预期一致, A和B组各占CPU总资源的 1/26 J9 G5 d6 g0 x' b8 [8 N
& z5 |& w& n  e

  D6 T' L5 P4 s* G" E" G8 n
: U5 c- r* e1 E3 t* d8 I+ Q8 R实例2 - A group 占用整体CPU资源的 2/3, B group 占用整体CPU资源的 1/3
4 B( u7 O( O' L0 J环境同 实例1, 不再重新挂载 cgroup 文件系统, 也不在重建 A 和 B
) m8 {. k9 x: i* {; VA group 的 cpu.shares 文件不变, 值为 1024( g7 a/ u* ]2 S2 V% [0 K
B group 的 cpu.shares 文件中的值改为 512, 这样, 相当于B占用CPU总资源的 1/3 (因为 512 / (512+1024) = 1/3)
) E$ M( ?4 z2 Z1 l. N$ r同实例1, 通过2个shell窗口, 分别是 A 和 B 的CPU使用率达到 100%, 然后通过 top 查看CPU使用情况5 q+ g: g5 t" e6 t3 d" u

/ Z" z* s4 K5 e9 }9 O# W2 K
9 F% }# K. [& D9 d  \# ^6 m复制代码
6 `" W9 a- n" \+ c& }2 n# 在 B 中shell 窗口执行以下命令
/ H' [. R5 _- K6 f* \+ @cat B/cpu.shares 0 w' W+ b( C* A6 Z6 x4 s; U
10247 M+ r+ _* l0 w2 J* X4 }9 u5 U% H
echo 512 > B/cpu.shares ' _& A/ q) k- j. ^
cat B/cpu.shares 5 @( d/ ~* m: E4 i% p  P
512
$ k- E3 M0 l) I1 }4 ?stress -c 23 v! Q+ C* |; P+ k' A2 d- ?
1 y0 F7 t; A, n/ j0 F" n+ q$ ^- k4 d
# 在 A 中 shell 窗口执行以下命令. a. u( S9 m: e5 h5 {
stress -c 2; }) h1 V& }6 w9 Y' h3 U

5 q  r! m5 u: g9 E5 K( N9 V: u# 在第3个 shell 窗口, 也就是 非A, 非B 的那个 shell 窗口, 用 top 查看cpu使用情况; w" B0 X# T1 {6 K
top
& {2 h( D, @' z% I/ @3 Qtop - 14:13:18 up 46 min,  3 users,  load average: 2.24, 1.92, 1.01) S  l" ~5 r: g
Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
6 t# s) g1 {) U  z( O5 U%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 E- Y% f$ T, H. i* H( F
KiB Mem:   1887872 total,   114744 used,  1773128 free,    10488 buffers
1 b% I7 {. z: |KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached1 H9 @  _4 p5 o* a* H

+ g& H# ]; y' l2 Q5 y PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      4 B  h- H" S3 `: l0 g, W
3376 root      20   0  6524   88    0 R  66.6  0.0   0:06.29 stress                                                                                                                       & M5 R" O0 p2 p4 U
3377 root      20   0  6524   88    0 R  66.6  0.0   0:06.30 stress                                                                                                                       2 u$ h- h# Y4 c
3373 root      20   0  6524   88    0 R  33.3  0.0   0:04.33 stress                                                                                                                       ; U2 u$ @4 j' T" X4 {7 K+ }0 j0 c7 @
3374 root      20   0  6524   88    0 R  33.3  0.0   0:04.32 stress               ' r0 K: U7 q% }; q! M  s: ^
" y9 a% B3 E2 S0 U7 I
# 查看这 4 个stress 进程是否分别属于 A 和 B5 e) Y9 I5 I$ F, r/ X: w- n0 J5 j
cat /mnt/cgroup/A/tasks 0 [+ C- t8 ]2 r
2945# a; o+ d; ]# ?& r3 |! ?7 u
3375  z3 y7 H. n' A( o
3376    <-- stress 进程
7 L" F, y8 v$ B+ u* l  s2 C3377    <-- stress 进程
- B2 d8 c7 t4 Bcat /mnt/cgroup/B/tasks
$ R2 z& C' a4 r6 _, h( [" m29965 L% ]7 A4 \0 O( }; T( O
3372
& l2 \# u& v& z5 j% ?5 C3373    <-- stress 进程
9 g; M8 a; O) C8 c% K/ t3374    <-- stress 进程
2 S) M& e  V5 f) i% B复制代码" ]  u: ]" g( l
很明显, A 组中的2个进程占用了CPU总量的 2/3 左右, B组中的2个进程占用了CPU总量的 1/3 左右.
7 o! j& C, T: a8 q6 T0 N% K
9 _9 n# Q  G- \" F0 n . Z% m: Q$ X0 e8 G

8 r& d/ u6 W1 Q+ z# \实例3 - 物理CPU的控制
/ n+ H* k0 P( w4 T( G$ {上面的实例中, 虽然能够控制每个组的CPU的总体占用率, 但是不能控制某个组的进程固定在某个物理CPU上运行.
; n' f# q0 k) y- U
2 ?& z' T1 A% ?7 B; ~5 x: [/ R0 @# M要想将 cgroup 绑定到某个固定的CPU上, 需要使用 cpuset 子系统.
4 O" i* C. ?3 a- y( T- N) f  _8 {  c  o" `  d. U" B
首先, 查看系统是否支持 cpuset 子系统, 也就是看内核编译选项 CONFIG_CPUSETS 是否设为y
$ z% B# e0 S6 e) x' _# `! u8 ^- k8 U1 ?/ L6 M9 Y3 a; h
cat /boot/config-`uname -r` | grep -i cpusets  S. @( s/ ~1 T" r" @2 ^
CONFIG_CPUSETS=y
9 I: v: \) m: K/ L3 c- h: S我的测试系统是支持的, 如果你的系统不支持, 就需要重新编译内核了.......
; W4 ?8 {: L7 a- H% Q5 d; y( H0 A! \* z) h; [5 Z7 L

* |- P3 Y7 X3 C! k; m6 n* W2 ~1 i- d  p/ [: F0 Y- K
然后, 用下面的例子演示将 A 和 B中的 stress 都指定到1个CPU上后的情况) [  @9 \" {  @) I( H
- d% C  `9 I  H* s5 Q1 t% k9 j
卸载当前的 cgroup! G1 b: o5 P4 `
再次挂载 cgroup 文件系统, 并指定 -o cpuset8 S' ~6 q$ T3 {, F+ g6 z5 m
指定 A 的物理CPU为 0 (双核CPU的每个核编号分别是 CPU0, CPU1)
1 y: d) U$ }0 j, ~8 M# _% r指定 B 的物理CPU也为 0, ]( N6 }% k- x- Z* S  v9 y' _
重复 实例1 中的步骤, 观察发生的变化: O- d4 V; T1 `- [9 i+ ?$ E

. W/ {; u# v) Q) j  m- M
! p$ n/ p! L* }& J. W- r; O复制代码1 [1 U8 C5 z- l5 B3 F" Z
umount /mnt/cgroup% q4 P& _, Q1 r, m6 y: X
mount -t cgroup -o cpuset cgroup /mnt/cgroup/
7 u3 T, K  @, o) }cd /mnt/cgroup" Q% `' s' ~' a
ls -l
  O) d* V6 P$ |* y! P* ?total 0
9 y/ y1 p. a; m9 f6 ^2 @" X+ @% R# e-rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.clone_children- `, l: A. j3 ]) s7 b8 R
--w--w--w- 1 root root 0 Aug 28 14:39 cgroup.event_control
9 s1 g2 Q3 |, ~* ?6 p-rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.procs
+ y" D8 f6 b4 A# [! x-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpu_exclusive
7 z+ T. D; g* x) Z+ G-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpus    <-- 这个就是设置关联物理CPU的文件/ g9 v; F$ t1 x/ u5 p
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_exclusive9 Q2 u( v2 N% r! |/ M4 g; P
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_hardwall
9 p* o9 i+ M- q1 e1 a-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_migrate6 v7 E/ i; U6 j8 `4 _3 h4 o) x/ [
-r--r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure& l6 o& w  ~% G, {, K3 p" ]
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure_enabled2 U8 L* E- f4 l3 O/ N, i+ m
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_page
: m: `' S  ]; x. r! ^2 i-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_slab8 U. X6 S2 z4 i- A4 s& Q
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mems* O) {2 q% K* B. x' a, F$ ^
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_load_balance
* Z% ~1 I3 w2 [$ O( g0 O7 D-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_relax_domain_level1 b; _6 b' l0 m, E  E+ ?: c: W
-rw-r--r-- 1 root root 0 Aug 28 14:39 notify_on_release
  ^# r& N& z0 [-rw-r--r-- 1 root root 0 Aug 28 14:39 release_agent9 K7 o' `1 x2 \& `7 A3 W7 d) Z' t
-rw-r--r-- 1 root root 0 Aug 28 14:39 tasks2 }5 y: J9 |6 B/ N

! |+ F( i1 v4 K# 创建子cgroup A 和 B
$ w3 q( V1 [( p" F+ {+ B+ Emkdir {A,B}
3 j: L* Z1 [* q( Pcat A/cpuset.cpus   
% Y3 U8 g& j4 b. b; h3 w1 L* I         <--  默认是空的( t8 s& O( o+ e: \7 _" w) ~
echo 0 > A/cpuset.cpus8 h) V( b/ n/ k  D" ~
cat A/cpuset.cpus
: q- `% L% }! o. h2 ]( R0# }6 I! L  E( m" `
echo 0 > B/cpuset.cpus   # 同样, 设置B组也绑定到CPU0+ W+ X* x$ w  @- b5 T7 ]
# 当前Shell加入到 A组) S. Y; Q6 {- f: t
echo $$ > /mnt/cgroup/A/tasks
8 m' u  R1 P- J, v, S-bash: echo: write error: No space left on device0 `. W6 R: y: a, M6 m7 M
复制代码
5 k- Q- v$ O$ q * r& _6 \: A( {
- A: C  r$ {, T3 W
如果出现上述错误, 只需要再设置 /mnt/cgroup/A/cpuset.mems 即可. (参考: http://serverfault.com/questions/579555/cgroup-no-space-left-on-device)6 [# c1 }! Y! N: x

1 O# S6 f9 Q% _9 v复制代码
7 n! {& a; |( d# 同时设置 A 的 cpuset.cpus 和 cpuset.mems# D5 W3 w  I7 k/ z/ v
echo 0 > A/cpuset.cpus
1 c  ]% [* @5 S3 m7 decho 0 > A/cpuset.mems, s3 O+ q" o, j3 j/ v( h, o
# B组也同样设置0 j2 Y, r- s4 ^% |, l, ~8 X
echo 0 > B/cpuset.cpus! d! n* X9 Y3 p" o
echo 0 > B/cpuset.mems$ |: }$ y' k% `- E$ [* p% N
$ M) v! V+ C7 f( g- D
# 将当前 shell 加入到 A组
* I* |# m& h1 F+ {- Gecho $$ > /mnt/cgroup/A/tasks   <-- 设置过 cpuset.mems 后, 就没有出错了
) d; A; d& h* G4 m- S5 w3 Q/ P6 |9 Y: |stress -c 2
$ T9 T7 X1 g, U7 n" K
; i0 @2 p6 p" U/ B7 E7 S# F! \6 L# 再打开一个Shell窗口, 并加入到 B组1 d6 [+ `. [' @8 u* {; r
echo $$ > /mnt/cgroup/B/tasks( o2 @9 y2 [) x$ T% T  Z
stress -c 2' Z+ m; I2 i  U( L5 X
5 O( ~& G# X! l8 H/ ^, Y9 Q/ I5 Q
# 再打开第3个 shell 窗口, 用top命令查看CPU使用情况
/ J) s3 D  \* X7 s" G. ^, k, I+ `: Z/ o+ ?top
  A) j- A0 a* z4 mtop - 15:13:29 up  1:46,  3 users,  load average: 1.01, 0.24, 0.120 T: H) Y+ c2 p# i% M
Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie# v0 g( E# r4 X- j2 k$ K+ V4 i; X+ q
%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 st2 y0 E$ }6 o$ C) l; q4 R" U
KiB Mem:   1887872 total,   117216 used,  1770656 free,    11144 buffers
# W  I* N: Y1 I& n6 e; u* e( HKiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
" \& x$ G% A  f2 q- m+ f' I
- c, Y! M( Y( _  w! m PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                     
# k  n. {( r4 @5 v8 v6 t7 M: O3830 root      20   0  6524   92    0 R  25.0  0.0   0:04.96 stress                                                                                                                       
" ~9 [; `- N* {- Z3831 root      20   0  6524   92    0 R  25.0  0.0   0:04.97 stress                                                                                                                       $ y8 c7 J  e7 _+ C' v1 G* {9 x6 W
3834 root      20   0  6524   92    0 R  25.0  0.0   0:03.56 stress                                                                                                                       
2 Q$ Z8 p  R9 ~1 j' W/ t  ^3833 root      20   0  6524   92    0 R  24.6  0.0   0:03.56 stress
# L7 H- ~7 w7 r) S+ {! z% O复制代码7 E* \, L* {4 a$ S: _
从上面的结果可以看出, 虽然 stress 命令指定了 -c 2(意思是在2个CPU上运行), 但是由于A和B都只绑定了CPU0,  I2 N' {4 m  v9 d$ `* H1 _

8 x+ E6 M( q% c+ j) a0 a7 r$ ?: D所以虽然是双核的机器, 它们所占用的CPU总量却只有 100%, 而不是实例1 中的 200%.0 g. s% I5 V8 f& [/ d
) q# K& n9 B/ p/ A, m6 Y) M
% G$ {  K2 x! g

, X! b4 j; `  V8 {# u- ^; U2 S8 F' f如果将B组的物理CPU绑定到CPU1, 那么应该所有 stress 的进程都占用 50%, CPU资源的总量变为 200%.6 S% T! k9 U" e6 |' _

8 W  q- j" y& G" _, P1 c- }0 }) h下面将B组的物理CPU绑定为CPU1, 看看结果是否和我们的预期一样." Y6 L4 @# Q2 {- W' O% ~
9 R8 c2 H$ X2 g* y, ]! u' n
复制代码
3 q; ^- R, w9 }2 G# 在 B组的 shell 窗口中执行以下命令
# v" v  U' A. P. o* yecho 1 > /mnt/cgroup/B/cpuset.cpus
; m" U9 [/ q$ v, G* a/ F/ E" Q% _cat /mnt/cgroup/B/cpuset.cpus
, ?4 W% ^7 |8 Z4 Q6 m8 {1
' B0 h# m. a. B5 Bstress -c 2
0 A- C0 Q. F6 V- j5 o2 r- X. {
4 A' p* [( }, h$ e( D7 |* o: n# 在 A组的 shell 窗口中执行以下命令6 l' N* J: G6 r
stress -c 2
+ n$ H+ L$ x* h
9 v- O4 v* d1 q( V' Z' K- t& S# 在第3个shell窗口中用top命令查看执行结果
# F9 d) E7 o6 w7 q  Ttop' g& l+ B5 h+ `7 T7 U! L) P
top - 15:20:07 up  1:53,  3 users,  load average: 0.38, 0.83, 0.566 A/ ?! S. \  P
Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie3 e& \; y2 Z6 x$ 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
& j+ H4 l3 Z0 \KiB Mem:   1887872 total,   117340 used,  1770532 free,    11168 buffers
% Z9 j+ I3 {  b/ xKiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
0 k* }1 x# C* o+ t# q2 L3 a% n" H0 U7 I: \9 u  d: ]
  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                        \1 v9 }" \! W6 Q. c2 {1 O
3854 root      20   0  6524   88    0 R  49.9  0.0   0:03.76 stress                                                                                                                       & G; k) i# A# T; G$ t
3857 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       * W+ J* A0 K) u9 R
3858 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       ; @3 Q) C: P# }
3855 root      20   0  6524   88    0 R  49.6  0.0   0:03.76 stress
4 m% b3 g8 {3 M/ H; d) R6 e: K复制代码# J* `6 F9 B5 T9 [& k
果然, 和预期一致. A组中的 stress 和 B组中的 stress 在各自的物理CPU上都占用了 100% 左右的CPU使用率.4 Q3 d- J2 c+ Q& x
" [' n* _- x( ^' o2 h
6 ]6 K% s4 E# W

3 Y7 d) ?) b# Q' `% h实例4 - cgroup 对使用的内存的控制' }# o. y0 A$ K1 e) N9 a
cgroup 对内存的控制也很简单, 只要挂载cgroup时, 指定 -o memory
( X: h# l5 E: i2 W, K! U0 J! c0 A3 `6 B
# 首先之前挂载的 cpuset 子系统) F# W% F. ?# I" Z2 ?
umount /mnt/cgroup. ]: o' ~1 l& P) Y
! F0 C" S( b9 ?
# 挂载cgroup 文件系统, 指定 -o memeory0 o) R' m' t9 V' `1 e/ y' G, O
mount -o memory -t cgroup mEMCg /mnt/cgroup/
6 b& X5 Y. S/ n/ _8 H3 m& y' omount: special device memcg does not exist
& S0 l5 k; j4 m/ U$ G: F . a4 y4 i$ `* p: M& T  }# z; e
1 s! A& f1 e) W$ H/ d/ y! U
出现以上错误的原因可能是因为debian系统中, 默认没有启动 cgroup 的memory子系统. 可以通过以下方法确认:$ ?* h# }/ C% R/ v5 X8 G' `
4 M/ Q* Q6 o; @- }
复制代码; Y5 d8 u; ?0 t* Q
cat /proc/cgroups ! e1 r* G7 @8 g4 f
#subsys_name    hierarchy    num_cgroups    enabled
( }( y) i7 z- h( Xcpuset    0    1    1
) |8 |- u  X- D2 @2 z; mcpu    0    1    1
3 y0 I8 X. t: vcpuacct    0    1    1+ I  |, ^0 s4 a: n) z+ S
memory    1    1    0              <-- 这里的 enabled 是 0
; w' f) [" \+ o% u8 C+ z3 Rdevices    0    1    11 }& v+ N7 ]! Q5 V
freezer    0    1    1
+ G; X9 E0 V9 G! J. h  knet_cls    0    1    17 z  c. B( b* K" J% m
blkio    0    1    1/ c6 w7 N9 t! V6 K4 G1 l/ e7 l6 @
peRF_event    0    1    1. A) O9 t  i2 x4 y# |
复制代码" f% j( T: g. u' [; L8 j: d

' J" U) z$ I3 R
. ]2 S" l" x1 d4 ]5 L/ r; l为了默认启用memory子系统, 可以设置 grub选项
" d0 h1 K/ V) N; B/ H  i9 V1 _# ?) U! Z2 {  I7 x4 T8 o* Y) G3 q: Y9 l
vim /etc/default/grub
8 M0 m6 D6 O% z# 修改 GRUB_CMDLINE_LINUX=""  ==> GRUB_CMDLINE_LINUX="cgroup_enable=memory"
4 u- X$ S2 D7 D# 保存后, 更新grub.cfg
# Q; X0 `  Z5 J: t$ f# _1 I/ Supdate-grub$ P9 v9 T0 [( W$ Z  {
reboot
4 R/ P8 [! W* O# C3 j" R" |' ^; c . N& H% [2 Y8 T; [, ~4 ]7 C

' [% K+ |1 H) J& k重启之后, 发现 /proc/cgroups 中的memory已经 enabled, 并且也可以挂载 memcg了
' `& A; W1 V# X/ Y0 ^
5 P0 c( W, o4 v4 K. d6 Y7 H. {6 P复制代码
# r- K8 T1 d9 L9 q: P  acat /proc/cgroups : B# x. ]& S4 L. |
#subsys_name    hierarchy    num_cgroups    enabled1 z* E, {4 e  I
cpuset    0    1    11 N% h) y' s. E6 \) Q
cpu    0    1    1! y" k5 S: E. S: r  k; s
cpuacct    0    1    1
+ A* p+ S% E3 j5 B$ ^4 ^9 _memory    1    1    1  }0 n; d7 w4 C% M6 g
devices    0    1    1
+ y) V; {# G/ T( b/ w6 g! \freezer    0    1    1
) V2 N) K7 \7 x+ c  `net_cls    0    1    1
! T$ u% ~8 {5 c: I3 }blkio    0    1    14 o7 z0 p$ H3 H/ Z4 N0 @. g, |" N( I
perf_event    0    1    10 A; k. f+ M7 u7 d5 \" C6 l, E

- z1 P0 R! S5 a# 挂载cgroup 的memory子系统
* Q. p' ~$ ~( o% |mount -t cgroup -o memory memcg /mnt/cgroup: j' y4 R- e- l0 X
ls -l /mnt/cgroup/   <-- 可以看到有很多 memory 相关的配置* S- {, p: g7 F, j4 a
total 0
/ x) r$ \" ?4 p-rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.clone_children5 j. h. x! U7 r6 X
--w--w--w- 1 root root 0 Aug 28 15:54 cgroup.event_control
+ @& y+ U; H! P8 `-rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.procs
6 J. a1 }6 K; f" w8 h! I-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.failcnt
# t2 \- F' S7 ^" S; k- G--w------- 1 root root 0 Aug 28 15:54 memory.force_empty
5 o: b: b/ B  ^- {-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.limit_in_bytes   <-- 限制内存使用的配置文件
, s! C9 G# Q& L- p  w. @-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.max_usage_in_bytes3 y/ T- E) m: g6 p4 u
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.move_charge_at_immigrate
0 u, z5 `7 `# u; }# A2 Q-r--r--r-- 1 root root 0 Aug 28 15:54 memory.numa_stat
# }, J+ N' R" _& F* J5 W-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.oom_control" D- Z( [2 c: L; ]# D) e  d
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.soft_limit_in_bytes3 [% T1 L# _5 s
-r--r--r-- 1 root root 0 Aug 28 15:54 memory.stat
6 L) Y: n; l4 e& n( i7 F; j8 n-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.swappiness6 P0 S1 i& Q! a# u
-r--r--r-- 1 root root 0 Aug 28 15:54 memory.usage_in_bytes
& `- [' @$ w0 |1 n-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.use_hierarchy
6 i; a6 O6 t9 f-rw-r--r-- 1 root root 0 Aug 28 15:54 notify_on_release
1 T1 d) S! @$ {. W3 w-rw-r--r-- 1 root root 0 Aug 28 15:54 release_agent
4 v; u5 L. n  n2 |  f+ P  J-rw-r--r-- 1 root root 0 Aug 28 15:54 tasks9 q) ~3 u/ Y7 U% i
复制代码
( P* ], G9 v* u 4 Q& a2 L- p$ ]4 e, F6 ]: q

5 ]& v1 J  a' g4 J" V3 O3 C开始实验:
% E9 x8 L  U8 V5 i$ w4 {* [7 E
' a) y8 P- I3 D% D# a重启系统 (为了保证内存的干净)4 R; \* P- A' G
挂载 memcg: B8 Q; M8 V6 w" [
在挂载的 /mnt/cgroup 中创建 组A
! G' Q( m0 @4 L7 @5 v将当前shell 加入到 组A
: H8 h) G$ r5 Z: m7 I不限制组A的内存, 压缩内核源码包, 并观察压缩前后内存的变化
! i( Y; g: J  _重复步骤 1 ~ 4) r+ U$ d5 U% N0 o  O' Z3 }
限制组A的内存为 10MB, 再次压缩内核源码包, 并观察压缩前后内存的变化, Z3 B7 X8 ^$ |- {9 i2 @- ~

+ `/ a% A% w" {( W
. s2 m$ Y. j) u% }复制代码, y( n1 b5 J. p0 q1 C$ n: F
# 重启系统
$ p6 A* i1 L/ Y2 hreboot: E% L( T! e: q( b1 h) u: q
$ @, n& t" w+ p0 }  U+ w- ]/ f2 t
# 挂载 memcg* G* o- k7 {* X* }
mount -t cgroup -o memory memcg /mnt/cgroup
1 `) C/ B& M! U5 V3 Q! v1 h7 a( Z
# 创建 组A# A! s* I) F. a9 t& m6 R8 U
mkdir /mnt/cgroup/A
9 S+ r8 n7 |" U* l7 q1 ~& z2 N6 Z
# 将当前 shell 加入到组A
" p6 a5 u( m6 |5 I' w. `+ w6 M0 }echo $$ > /mnt/cgroup/A/tasks
8 G# n: F9 x* ?0 z  e  e  k; S/ H5 Y0 Y. T- ]
# 测试不限制内存时, 内存的使用情况, 这里不用linux源码也可以, 但最好用个大点的文件夹来压缩, 以便更容易看出内存的变化., G0 C- j6 {) r+ F
free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;8 [( }; t# {# L6 O2 z9 |
             total       used       free     shared    buffers     cached
/ n3 ?/ w1 k8 }+ U& j3 F  xMem:          1843        122       1721          0          9         43
- D2 C4 M4 L2 o-/+ buffers/cache:         68       1774; G' b* ~) }9 m8 O
Swap:         3888          0       3888& _( F8 C9 b: k  Q4 ^4 @
             total       used       free     shared    buffers     cached. u! i4 e& E' D) s8 m/ F" p! m
Mem:          1843       1744         99          0         26       16142 |/ S: ^2 U% ~' K' ]9 d
-/+ buffers/cache:        104       1739
7 z! b/ {* R( a( d' u: e  u* ISwap:         3888          0       3888
  l, D4 r# f+ ^. P. Q0 P9 E, ]4 `, o' u6 ^$ {
# 重启系统
  A% t8 t) ~: S  k) @reboot/ ]- h) |% V+ G
0 Y8 l# J5 D+ O4 ]. }4 z
# 挂载 memcg
* ?" Y5 T1 g5 `4 y3 b' |3 |mount -t cgroup -o memory memcg /mnt/cgroup
3 J2 Z$ j8 X  f* u) M+ K! E' ?) @7 h6 H. u: j' X6 m1 R
# 创建 组A
% N' H) G7 {( T9 X, Bmkdir /mnt/cgroup/A+ L0 w$ f3 Y% e7 n

  g4 t. m  K6 O: Y3 [7 M, C8 r# 将当前 shell 加入到组A
; k; ^# `  z5 ^+ f0 c, R  M& |echo $$ > /mnt/cgroup/A/tasks. u$ ~* g7 n! X5 t' h
' x' d5 `1 W- e0 g! o3 c6 q
# 限制 组A 的内存使用量最大为 10MB3 M- {  a7 m& P  D& a3 s
echo 10M > /mnt/cgroup/A/memory.limit_in_bytes+ Z; h4 g3 ?% U7 K, Q4 w

# J: @7 S; ?- m. u+ S) j4 H# 测试限制内存为 10MB 时, 内存的使用情况.
; m* Y2 h0 T5 N& N6 B; |rm -rf linux-source-3.2.tar.gz* `) I  i: G1 G4 O1 ^; G( y9 H
free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;- w* n3 r- q) V, r! R* b# ]
             total       used       free     shared    buffers     cached$ G  i; \3 ^3 T
Mem:          1843        122       1721          0         10         438 G& [) [9 n" q+ I+ O
-/+ buffers/cache:         68       17744 d! G7 ]2 e. q1 ]# T
Swap:         3888          0       38887 N7 C& w, d9 k+ Z; l6 G: i( s
             total       used       free     shared    buffers     cached
8 i$ X4 a. k5 n5 HMem:          1843        194       1649          0         14         48. Z" |" F. |4 G  K
-/+ buffers/cache:        131       1712
6 J7 K" I2 G. V% I0 B# LSwap:         3888          0       3888/ y$ I6 c3 z6 d! r
复制代码
! j& x* p% M, ?6 P* p从上面的结果可以看出限制内存是起了作用的.* E& r6 u! b& O6 i; ~5 r
& P' e( m' G0 {0 X" r! Y# q
不限制内存时, tar 压缩前后 buffer + cache 内存从 (9MB + 43MB) ==> (26MB + 1614MB)  增大了 1588MB- V8 ?; O5 W/ g; K3 K

. V4 p4 U1 c& Z* A5 Y& k( Z限制内存后, tar 压缩前后 buffer + cache 内存从 (10MB + 43MB) ==> (14MB + 48MB)  增大了 9MB8 a9 f3 ?( k' J; T$ W5 ?

# O6 m8 x3 ?2 z1 ? ' ?+ S3 H, n7 \

% \, w5 z( X' n0 X& Q总结
4 `+ S+ R0 _* m0 n! ]9 P简单的实验就发现 cgroup 如此强大的控制能力(而且配置也很简单), 这也就难怪LXC等容器技术能如此强大, 如此流行.
) R: o" F* n: y5 l  {
9 P( g" f4 ]; Q$ l7 m/ G5 f# ocgroup 的配置文件很多, 上面的实例中只简单使用了其中的几个配置文件, 如果想深入了解 cgroup, 更好的利用cgroup的话,% c( P1 I* B# q: C9 f

, h0 l4 r! J  y. w" |7 l7 p1 J! r* c' q还得找个介绍cgroup配置文件的文档来研究一下, 这篇博客提供的内容还远远不够.
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-24 22:13 , Processed in 0.203125 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表