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

Linux资源控制-CPU和内存

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
本帖最后由 mytomorrow 于 2020-9-8 18:08 编辑
8 V3 o4 @$ P2 m& D0 U' `2 F$ J4 a' y; g* K1 ~  G2 F
主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法。
0 T" Q0 \: a, T6 @. L% [' p- t0 x1 i- u9 N% H: }* l! x) k

$ b' t$ V# R* z' j
; M' D% z, k- k3 _8 K1 HCPU资源控制$ @' }  J8 J3 p6 S) Q
每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的.2 s3 c7 d- y( p, k4 F

* D6 T  Z, S! TLinux系统中有多种调度策略, 各种调度策略有其适用的场景, 也很难说哪种调度策略是最优的./ X7 K, _" l  Z+ Y- g1 y7 R# w

: R3 Q( Y3 R0 S4 u1 FLinux的调度策略可以参见代码: include/linux/sched.h9 {% k- |6 G( n$ D- D$ w
# B2 J, x7 a# X1 Q3 Q7 r$ x
复制代码
# l: ~! e3 i5 @4 z' Z: G; Z2 K/*
' I6 v8 H1 [6 D * Scheduling policies
2 A7 z2 O) K9 p6 m */0 Z4 p8 x  _4 E  i2 l  Y
#define SCHED_NORMAL        0
4 q: ~0 ]; y. m; E# \#define SCHED_FIFO        1
# Y! L! k" ^7 ]1 E$ V) a#define SCHED_RR        2
, V; [' F: t1 _9 z#define SCHED_BATCH        3/ Q6 Y; a3 [9 z4 i: v! F& \# V
/* SCHED_ISO: reserved but not implemented yet */
" }. q1 y7 x8 t1 ~( z# e" T#define SCHED_IDLE        5
& f) u- j7 x5 A3 {; _3 g$ d: X, h/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */, ~, C% a8 R4 Y/ T; P) W
#define SCHED_RESET_ON_FORK     0x40000000( l% C2 f2 u# A  d8 k) O  E! L
复制代码
% D! j$ a2 ^3 R" {( ]! y $ l6 C/ ~1 x2 r+ g" J, g1 n

5 r; M4 z" L3 `% j% j# JLinux 系统也提供了修改调度策略的命令和系统调用接口.
* J; v5 F0 m' ]6 Q! U" B, j0 S6 G
调用接口请查询相关文档, 这里主要介绍一下修改调度策略的命令 - chrt.
4 r& t$ r7 @& l. C
6 P" [( e+ d& P% M. Q/ G; C复制代码: ~/ U8 |: U: j3 D6 V
# 在一个终端中执行% T; Z3 s- J* `6 Q+ E" j
sleep 1000
0 Q3 {- |; F& G# 打开另一个终端( F8 e3 c0 ^  k8 |
ps -ef | grep sleep  # 找出 sleep 1000 的pid, 这里假设是 1234( ]1 _; B; B8 H, t% U, H
chrt -p 1234         # 可以查看 pid=1234 的进程的 调度策略, 输入如下:
0 i' N; r" Z- O' c" q      pid 1234's current scheduling policy: SCHED_OTHER7 o7 S# z) m7 n# b
      pid 1234's current scheduling priority: 0
. y7 N7 Q) ?% W4 W- Z; L# k$ {/ z  }2 `  k
chrt -p -f 10 1234   # 修改调度策略为 SCHED_FIFO, 并且优先级为10, y0 e' K0 `% U
chrt -p 1234         # 再次查看调度策略9 p& R# g; r9 j1 F# u+ h2 W0 T
      pid 1234's current scheduling policy: SCHED_FIFO
- ]9 n, d2 R; ~0 R2 ~1 f& ?4 t      pid 1234's current scheduling priority: 100 D- t4 M+ B; W( L2 b" \
复制代码/ Q  J2 x* J9 J/ l% d9 k

  w9 D$ X" I2 G1 x; l, _* H8 h  l* B7 f1 u, O) b4 C; |
补充:% p4 j) i' b2 R) J$ ?; o/ n% V
6 e: m% _: A! O5 x5 ~+ D% w
chrt 也可以直接指定一条命令, 并设置这条命令的优先级的调度策略, 具体查看 chrt --help
4 V3 j- e9 I6 ]. y; K: ~. G查看一个进程的调度策略, 除了使用 chrt 命令之外, 还可以 cat /proc/<; PID>/sched
) z5 \' v) Q6 p( Q* Y3 R. H 2 C: Z+ L0 `* D9 N3 Q+ Z

- j; B8 T! J% j5 n7 }实时进程的CPU控制
7 z- Z" T2 N' ^; p5 y, u所谓的实时进程, 也就是那些对响应时间要求比较高的进程.
: z  Z# X0 o1 I2 Z3 f; s
" M7 @" T, B$ _$ a8 z4 Z2 D  z/ W9 A这类进程需要在限定的时间内处理用户的请求, 因此, 在限定的这段时间内, 需要占用所有CPU资源, 并且不能被其它进程打断.
$ B" W0 P2 b' Z8 |$ P- u
$ L1 I* m6 b* O7 J' K3 H* h( y在这种情况下, 如果实时进程中出现了类似死循环之类的情况, 就会导致整个系统无响应.
) C" ~* O3 L% o8 L! ~8 z5 h. _
' S* z- G% f- C因为实时进程的CPU优先级高, 并且未处理完之前是不会释放CPU资源的., V6 X- U- }- Z( p$ I: v) D, ~

" g. N  |  C1 w  c ! u6 R: f, G$ u' K* i

* G, a4 t) M5 _1 Q' R所以, 内核中需要有一种方式来限制实时进程的CPU资源占用.
4 ?$ [( r  |7 b% u/ Z7 b! H5 I% X9 p) x4 W5 i
, ~1 H# z- Q# m8 d2 F4 p& [3 O

. Q( b9 R4 [! a3 E5 R  e系统整体设置
: l) a) d& Q5 M" g1. 获取当前系统的设置" W; M4 @$ ^2 h7 V
; u; l8 Z$ Z4 p5 W7 ^
sysctl -n kernel.sched_rt_period_us   # 实时进程调度的单位CPU时间 1 秒
# P& H2 V" {' j. M# w' A' @1 k1000000
0 d. Y8 R" T2 |- A6 d1 Nsysctl -n kernel.sched_rt_runtime_us  # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒, l6 v: i. e( D8 l7 }; u# K! H
950000
9 i3 z! X1 |5 m4 y  \这个设置说明实时进程在运行时并不是完全占用CPU的, 每1秒中有0.05秒的时间可以给其它进程运行.
6 y, T* Q$ d& R3 \4 e  G4 q& M  |3 }% P, ]1 V) I; w" d- C2 X4 N
这样既不会对实时进程的响应时间造成太大的影响, 也避免了实时进程卡住时导致整个系统无响应.0 c+ s1 T" ]: T4 E' b% p
9 C7 S" j1 @9 _  o8 j; _

" [2 }% C, d' M6 I2 l" w* d6 h# Q  z; |- D3 j# @% V; R
2. 设置实时进程占用CPU时间) O6 K4 u! i% g% ?, Y

. ~! D1 n4 j( T& ?上面的默认设置中, 实时进程占用 95% 的CPU时间. 如果觉得占用的太多或太少, 都是可以调整的.比如:! a/ S/ f4 I1 Z: q. E3 a
3 k5 h2 U' X6 j$ X
sysctl -w kernel.sched_rt_runtime_us=900000    # 设置实时进程每1秒中只占0.9秒的CPU时间
) W1 Z8 N' d$ f- w1 ]( O! k5 ikernel.sched_rt_runtime_us = 900000) ]$ [8 g+ o& a) s: {
sysctl -n kernel.sched_rt_runtime_us 9 X* X/ _4 q* \/ o6 K4 Z0 l, M
900000
! ]( P, R, C: S; F0 k. a
0 h& x' ~) Q  A" r* X7 `
+ |# J; I; w9 h  F3 [cgroup 中的设置* Q% _8 }6 _5 `/ b" p' N( E- O
整体设置是针对整个系统的, 我们也可以通过 cgroup 来对一组进程的CPU资源进行控制., d" d5 h8 A. f4 s" w0 v
. m2 I3 h: q, H- S
如果想在 cgroup 中对 sched_rt_period_us 和 sched_rt_runtime_us 进行控制, 需要内核编译选项 CONFIG_RT_GROUP_SCHED=y
* y$ I' M/ X( S! B) g2 N0 o
* a: n5 A/ T' c- x查看当前系统的内核编译选项方法如下: (debian 7.6 系统)7 v! ]7 }! S" M0 S

( L9 B! h0 Z4 y0 A4 |2 C, O) Xcat /boot/config-`uname -r`/ B& j7 y2 H" }  q# I( ~& H7 O
查看 CONFIG_RT_GROUP_SCHED 是否启用/ g  [: N4 U$ S  E+ s: M
2 [) E2 F+ L$ Y- F/ p
cat /boot/config-`uname -r` | grep -i rt_group5 j4 e" O7 t8 ?' _" E4 q3 T
# CONFIG_RT_GROUP_SCHED is not set
( Z3 P8 y- P9 ~+ \9 odebian 7.6 默认没有启动这个选项, 所以挂载cgroup之后, 没有设置 sched_rt_period_us 和 sched_rt_runtime_us 的文件
4 G! K- y" _; [5 ~0 I  }) J3 m8 j4 ]( k* x; l* Y# H
复制代码0 J$ W- n, o1 _2 q; ~- ~
mkdir /mnt/cgroup9 M4 _5 b, c2 n/ Q4 K! M$ h2 I% v
mount -t cgroup cgroup /mnt/cgroup/5 o1 a  d# X# F
cd /mnt/cgroup/) ^! K! w; ~) K$ g+ Z0 H
ls -l/ G* j. N: H- n
total 0+ r& F7 Z3 U  |( q/ U+ X. o9 d
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_merged3 J6 b2 o0 v, [% Y
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_queued7 L7 g4 S* S' x% N
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_bytes4 g. M, C2 s5 j5 U( N# G+ h
-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_serviced
2 x3 q" C+ f( J! T-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_time
" N1 N) O) g! u-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_wait_time# a! H( s9 `6 h; U1 M/ r+ I
--w------- 1 root root 0 Aug 28 09:06 blkio.reset_stats
% ~- e0 O4 t! t. c4 h+ E$ M- j-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.sectors
( D0 q% W; _6 _: e; n) ]-r--r--r-- 1 root root 0 Aug 28 09:06 blkio.time2 t" Q! z3 m. A9 P* |: n
-rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight* @1 I+ N3 t) a; q( T2 a( \7 E
-rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight_device$ P  l. X5 T  Y  P
-rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.clone_children
$ U; v: d+ C  k' W+ S--w--w--w- 1 root root 0 Aug 28 09:06 cgroup.event_control  l4 ^0 t) n2 ~& U
-rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.procs
/ t8 h8 J3 w; A4 f7 b-r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.stat$ M3 m5 X7 x0 Y+ [& |
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage- s+ W; |8 S6 E  b: [: i+ w% l/ M
-r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage_percpu
* a. F8 W1 b+ I" @9 }' c1 R( A-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpu_exclusive
# P+ P$ Q! P1 B. G' ]-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpus
/ ]. I1 o& ^4 c5 U-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_exclusive
; @+ B+ [; f2 Y; ]-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_hardwall
) u# }1 a5 z" |2 V( `7 ^* S! ?" f-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_migrate( u! y1 M) t4 ]
-r--r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure
) v8 _/ I* m% z- F-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure_enabled+ \( z; t/ r4 L5 q( F
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_page0 w- d$ j( r% {4 H! X
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_slab, d$ C5 d3 F2 D
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mems4 F: o7 ^- b  R; O; O
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_load_balance9 a9 q6 W5 Y' U' W: Q8 V, T
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_relax_domain_level& m* ]/ B1 l, B) j8 ?- Q
-rw-r--r-- 1 root root 0 Aug 28 09:06 cpu.shares
7 V  x4 K& q8 T; Q1 X' `' I--w------- 1 root root 0 Aug 28 09:06 devices.allow
% k. @! q, z% r--w------- 1 root root 0 Aug 28 09:06 devices.deny
; @5 t* _6 ]. |* J4 E, y) x-r--r--r-- 1 root root 0 Aug 28 09:06 devices.list& f* L* |" B, {. p6 @
-rw-r--r-- 1 root root 0 Aug 28 09:06 net_cls.classid
: v' \0 L. d: _% H; b" s-rw-r--r-- 1 root root 0 Aug 28 09:06 notify_on_release. h  C) ?. \& ^: S% F# |
-rw-r--r-- 1 root root 0 Aug 28 09:06 release_agent
2 m' O+ ^' ?' r- d2 j$ ^8 e; t-rw-r--r-- 1 root root 0 Aug 28 09:06 tasks
2 l6 J0 l% S' w8 A% t& g* r% T复制代码6 {9 i, m# r' P( D$ O' a. e

9 l1 e: J- X# G2 `
# z0 m9 ^- ]5 @: s/ n果然, 只有cpu.share, 没有 cpu.sched_rt_period_us 和 cpu.sched_rt_runtime_us1 g; t( N% X) C: q; s2 v5 B
) t1 d4 d' o& Q" r* n
没办法, 重新编译内核, 编译内核的具体方法参见:  编译Linux内核+ Z9 ]. F' f! v" M' O+ ^
" X$ c' O1 }( d0 u: @; F
为了节约时间, 我们用 make localmodconfig 来创建 .config 文件, 然后修改其中的 CONFIG_RT_GROUP_SCHED=y
+ ~/ Q7 B8 X: J  M) r" l3 j, `1 n- Z+ i( ^7 e, i2 s4 y
下载源码等等参见: 编译Linux内核, 主要步骤如下:
. s' H/ ?( v& u; f& d; f
% a  ]3 B" o$ `! J3 N. u复制代码
* G' y) Q+ Y  B6 w: _cd /path/to/linux-source-3.2- T: B+ j) P- x8 U
make localmodconfig
0 g0 V6 k1 }4 z6 v6 ?vim .config   # 设置 CONFIG_RT_GROUP_SCHED=y 并保存" h* N+ ?5 E5 N: k
make! A8 o9 R! ^2 t
make modules_install$ K- V9 [# Y8 ?7 H& B( t
make install
7 R/ e7 X7 v: Z6 H7 `reboot      # 重启之前看看 /boot/grub/grub.cfg 中, 默认启动的是不是新安装的内核
# F2 ~) b$ h$ q* _1 a. a2 ~复制代码% G5 A; g0 T. s7 X! T
+ \) [3 x" y' `) o9 _
启动到新内核, 再次查看内核选项 CONFIG_RT_GROUP_SCHED 是否启用
/ f8 J' {9 K3 F$ S/ `: D* Y& u- _# s% ^# K
cat /boot/config-`uname -r` | grep -i rt_group6 K" H  l' `% o! H; ]5 S: _- z
CONFIG_RT_GROUP_SCHED=y       # 已启用% a6 s# m4 @$ p% d5 d4 g

% F1 w: b5 M' m3 d0 `2 E) ]( k3 W# L0 g5 c0 Q9 W- F! f
再次挂载 cgroup 文件系统, 发现多了2个配置文件, cpu.rt_period_us 和 cpu.rt_runtime_us
2 }; S0 z, L  X# Y+ o4 o& J
( l' n5 q/ M0 R* Q' }6 ?2 o% F复制代码! V0 x  q& B8 I
mount -t cgroup cgroup /mnt/cgroup/
: I* g8 B+ w* L2 ~. H: ^6 hcd /mnt/cgroup/
* c( S/ C+ d0 i  U& i( P* Els -l, o9 R! g2 U( U
total 0
% _1 g1 K, z& V6 o-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_merged6 ~9 ?! J6 O$ a* \  @0 `
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_queued
& T, R. h5 J3 }$ ]5 R-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_bytes3 X, z* F2 K5 P0 r
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_serviced$ D- [: b4 D2 g1 k% N7 k
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_time
! @& F) u$ W. V. \+ g-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_wait_time$ ?% o" z' q- r" D' D& A9 ^( z8 W- `  b
--w------- 1 root root 0 Aug 28 09:53 blkio.reset_stats
, N# l2 W7 G* C% x% G4 d/ I) P4 z  r# P-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.sectors  S1 Q# [9 f6 }" A. n
-r--r--r-- 1 root root 0 Aug 28 09:53 blkio.time% E2 K8 h3 u8 i5 J
-rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight* r  ?7 Z# r4 G: S/ W0 ?; N
-rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight_device5 Y5 @+ y5 ]# f8 U1 L0 g
-rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.clone_children
$ F! [* Q( s+ K--w--w--w- 1 root root 0 Aug 28 09:53 cgroup.event_control3 U& R" s9 L+ a: U5 w4 y
-rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.procs
, Z( ^* M# O. w  m$ l& ]& }-r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.stat
7 @1 n( a8 y$ [9 u; A! l-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage& j  A7 X6 i- ^: R
-r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage_percpu' G. z$ N( O6 r5 f2 G
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_period_us7 a0 j5 u+ v# C$ n$ ?/ Z0 D+ g
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_runtime_us* ~% K; }; Q& P8 Y, S
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpu_exclusive
# v3 `4 X7 ~4 a% u. @: E2 a-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpus
1 ~! m% @7 V* Q* R1 P3 |-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_exclusive- l0 n8 V) `# ]
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_hardwall
0 ~' }- y! X6 @+ j+ [-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_migrate
% {8 Y$ i  U6 H. X  u-r--r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure
6 ~# Y2 G( U& U4 k5 r  C: z-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure_enabled
- g2 I7 U1 y1 K/ ?-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_page
2 u& u/ ^% y* k! q6 a-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_slab9 o( t( B2 u& F9 O
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mems- y- `, H! ?% z/ J7 J
-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_load_balance
# e3 Y& k, G2 i4 M( b-rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_relax_domain_level
* ~# @7 u2 V8 ]+ w1 q: j, O-rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.shares
- X8 S7 S6 p" P6 y& o--w------- 1 root root 0 Aug 28 09:53 devices.allow& X1 P) R2 F$ o+ p
--w------- 1 root root 0 Aug 28 09:53 devices.deny
4 l4 G) H2 g/ t  b-r--r--r-- 1 root root 0 Aug 28 09:53 devices.list
2 y/ e3 i: N+ E& b-rw-r--r-- 1 root root 0 Aug 28 09:53 net_cls.classid
9 I' Q$ W" t4 i; v8 U$ @( ^9 b) a5 E-rw-r--r-- 1 root root 0 Aug 28 09:53 notify_on_release/ s% T+ }$ A& S
-rw-r--r-- 1 root root 0 Aug 28 09:53 release_agent
2 }9 M+ j: G) k+ U2 T4 ?-rw-r--r-- 1 root root 0 Aug 28 09:53 tasks# W% k$ W4 W0 C$ s6 z# ?' g
# H+ d' \6 X4 K" R
cat cpu.rt_period_us 8 l6 f1 Z& k! P( T! m" l- C
10000004 T. R  V: R! W) V6 a
cat cpu.rt_runtime_us
7 Y$ H: x6 \* U$ C1 e950000
3 T9 C5 d! _, V% q复制代码' d$ O2 C6 O; }3 B9 ~
( j) l2 K0 ~$ g" Z7 L( l) n- T0 C

5 L9 t5 s7 A- z$ E3 ?6 g通过配置 cpu.rt_period_us 和 cpu.rt_runtime_us 就可以对 cgroup 中的进程组中的实时进程进行 CPU使用时间的控制.
9 e$ l" s+ k( i8 ^1 t8 F$ H3 k
' C: ?6 F; H7 z " b% ?  v" B9 L2 G% P1 }( y/ ]
' V$ {8 L7 H* _" |7 X# E
资源控制实例
: w8 h/ |) ?2 P7 [% J) B$ `上面主要介绍资源的一些理论基础, 下面通过一些实例演示如果通过 cgroup 来控制进程所使用的 CPU和内存 资源.5 i; _1 P3 I  `" J! x; \+ m. n

/ J) I7 z2 Y0 W8 x% D$ ALinux对CPU 和 内存的控制有对应的 cgroup 子系统 cpuset 和 memory
  [0 W9 |. k- ~+ D
/ y: a, ]. a$ y0 a+ t
$ q0 N* s, M- I5 q5 Z1 t+ y( _% K% d$ P) k" A
实例: cgroup 中对其中 *子cgroup* 的CPU资源控制3 a6 S6 _8 U& l1 W+ K& \4 j7 {4 {
对各个 *子cgroup* 的CPU占用率进行控制主要依靠每个 *子cgroup* 的 cpu.shares 文件2 @3 F; ?5 V7 l7 w4 e" d- o7 F
9 c) b* G- C+ l8 ]% _
直接用实验过程来说话, 其中加入了一些注释.0 L- B0 r0 B% e# f4 y
6 Z* V5 m, f) G: l0 m) D9 T9 h
# 安装需要的软件
: ]! t# i) \! m* U* N, Mapt-get install stress     # 让CPU达到 100% 的压力工具
% f0 h5 c5 ~3 m. I6 eapt-get install sysstat    # 查看系统CPU, 内存, 磁盘, 网络等资源使用情况的工具
7 G* S9 Z/ X, [! v/ c, `9 P8 M
% e! `' J* O! c# M
! L( ]- d, E% o3 Q. R( S1 \) m实例1 - 默认情况, A 和 B 各占CPU总资源的 1/2
) o8 ?! l! M- H% Z! _& f  }挂载 cgroup 文件系统 (注意加上 -o cpu 的选项)
! U: ~* b/ G" T/ C) |, h在 cgroup中创建 2个子cgroup A 和 B1 Y7 N( a- b2 {$ a2 N
默认情况下, cgroup A 和 cgroup B 中的 cpu.shares 中的数值都是 1024
0 T9 D1 ?0 S) e5 H9 I  D" N在 A 和 B 中用 stress 工具使其 CPU占用率达到 100%. M) U7 `! e# W+ s3 P# s/ L
top 命令查看 A 和 B 中进程分别占用的 CPU (应该都是 50%)5 o% [. Y- e$ g( r: o" N

7 x5 O$ p) k$ i1 z0 D6 |) e, w  x, N# w+ x/ A8 Y  J! C+ `4 t6 G. u  d
复制代码
1 e' `: i5 w) g3 }5 u3 c# 挂载 cgroup 文件系统
4 R9 `  F7 K4 |% v' M$ b& |# B' {mount -t cgroup -o cpu cgroup /mnt/cgroup/
! W; I+ Q) @, g6 t: tcd /mnt/cgroup6 V; N7 ]5 B  M6 u
ls -l
* v8 e9 Z( d6 z$ A: L( p' O7 jtotal 0
8 ^' R9 f) X% }% l. c-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_merged& `0 h: t8 k7 e& f, i" v. j
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_queued
2 F" Z9 H4 c% ^6 ]-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_bytes# {, e$ p; b7 P6 ~" g
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_serviced5 r6 q1 _# R* e4 a+ b: k7 L0 O8 h
-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_time
% E( L' v7 m! L# v) E, _/ R2 x+ ~-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_wait_time
2 n) x6 f/ P3 S" F--w------- 1 root root 0 Aug 28 11:29 blkio.reset_stats
! x3 J7 l! j7 Z7 e-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.sectors
4 ^# Y5 ^: K: h-r--r--r-- 1 root root 0 Aug 28 11:29 blkio.time
& Z) H' z# Y5 t7 l7 S. c5 l* W4 c-rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight
* G0 f' U& N; {9 f1 @-rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight_device+ _: [2 J6 K- M+ h+ ]% n, p% q
-rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.clone_children
4 l' q) \8 m+ y3 l--w--w--w- 1 root root 0 Aug 28 11:29 cgroup.event_control1 u) e* `& t" j! c, M4 v( ^% j
-rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.procs8 z3 Q  g+ Y! l* Q
-r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.stat
6 X7 j+ H* e: l, l  ~5 x" M-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage
' Z' b5 D! X8 p-r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage_percpu
% W4 O2 j+ y/ |8 _. @-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpu_exclusive- d) G: a; p# j/ B
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpus- S' E0 A" h* q4 [
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_exclusive, S7 c; Y9 I: t+ p/ S
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_hardwall
0 N; w6 a/ V9 M9 f4 a5 N9 T-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_migrate
/ L- J4 y6 g$ P6 e) Y6 ~-r--r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure6 C& z6 ~( o+ ?4 w
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure_enabled( F! }8 X: O# s
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_page5 \, W, I- k7 n9 x
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_slab
) ]' K7 x& L8 B2 j8 n8 U-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mems! o% b$ H( _" U& v. b/ L+ d, ]/ B/ ]0 x% f
-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_load_balance
- V8 N8 t. E1 ~, y6 g-rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_relax_domain_level
- n5 W! g' \8 U0 T; X  ^& h2 T-rw-r--r-- 1 root root 0 Aug 28 11:29 cpu.shares0 v" P, w  F$ ^
--w------- 1 root root 0 Aug 28 11:29 devices.allow
( u( u7 D+ H8 G  v) Q# p4 @- a--w------- 1 root root 0 Aug 28 11:29 devices.deny: \! ~* n" _% x5 f
-r--r--r-- 1 root root 0 Aug 28 11:29 devices.list
' w6 x5 S6 K( I' `+ n$ n& Z-rw-r--r-- 1 root root 0 Aug 28 11:29 net_cls.classid3 c% @6 D- R; e2 s, N  ^% s
-rw-r--r-- 1 root root 0 Aug 28 11:29 notify_on_release0 P% {5 Q2 U; ]' @
-rw-r--r-- 1 root root 0 Aug 28 11:29 release_agent/ X. F/ l% t" [4 L9 z8 F8 K
-rw-r--r-- 1 root root 0 Aug 28 11:29 tasks/ H: F1 {# C2 I5 _9 d) z$ X0 o
8 K" d' k# z, B
# 创建 子cgroup A 和 B
. |& G  Y! ?' Lmkdir {A,B}- W! d- Z7 p* J0 }1 X/ g( J
cat A/cpu.shares
& i, z# s+ A3 A1024
4 l; q# v) H2 c& Ocat B/cpu.shares , c$ `" |. ~1 Z% q2 N. P
1024  Q9 d) s' G& C4 n
) M3 O: M- f  \; t) e
# 在 A 和 B 中分别通过 stress 工具使其CPU使用率达到 100%
! k8 L- `' ]- @8 O$ ^% d" Yecho $$ > A/tasks  # 将当前的 SHELL 加入到 cgroup A中6 T) v* }, h1 v
stress -c 2    # 这里-c 2 是因为测试机器是双核, 要在2个核上都产生 100% 的CPU 占用率
, {5 E1 H5 f! M1 s- ^9 {( F# 另外打开一个 shell 窗口, 并将这个shell 加入到 cgroup B中& Z5 `* _6 u! M  G
echo $$ > B/tasks  # 将当前的 SHELL 加入到 cgroup B中
2 D8 _1 J  ?6 v2 P! {stress -c 2    # 在2个核上都产生 100% 的CPU 占用率, m1 Z  T0 ^# g  t
# 再打开一个 shell 窗口, 用top命令查看 CPU占用情况( L2 r9 S6 _# R5 y
top
( G- l7 H& E! L: g" xtop - 14:10:32 up 43 min,  3 users,  load average: 2.31, 1.24, 0.623 _$ A8 {) p3 ]# k8 a/ P1 N; J
Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie, C3 O+ _7 }0 e9 C- n7 G
%Cpu(s):100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
1 x% K1 o5 X* C/ p& U$ YKiB Mem:   1887872 total,   114744 used,  1773128 free,    10472 buffers7 `0 ~6 r# \/ {, o1 W) N
KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
/ E1 B: |( P3 ?
) W+ i- u9 W4 P2 A: h PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                     
1 A6 d4 o3 T3 U4 m6 J" E/ E0 C3350 root      20   0  6524   92    0 R  49.9  0.0   0:08.73 stress                                                                                                                       % N5 N: ]; ~! ~) \6 N, _
3351 root      20   0  6524   92    0 R  49.9  0.0   0:08.67 stress                                                                                                                       4 c. u9 G6 z& S: S$ ?
3353 root      20   0  6524   92    0 R  49.9  0.0   0:07.35 stress                                                                                                                       
' ?6 l0 t& c; g" U3354 root      20   0  6524   92    0 R  49.9  0.0   0:07.36 stress                    ( \  j- @; Z5 n; [2 ?
: F: |# x% ~+ f. @2 O% t% Q
# 查看这 4 个stress 进程是否分别属于 A 和 B
1 r* x. m3 K! j1 g5 B6 ?- Y$ mcat /mnt/cgroup/A/tasks
& z+ r, ^/ l( G4 q& M2945
1 f& P, \7 Z4 i$ S3349; E7 w& T" M7 g0 F
3350   <-- stress 进程
4 T  _0 X, s1 M4 s" }( E3351   <-- stress 进程
0 k9 E, s3 G& ~  o& Z# _7 _cat /mnt/cgroup/B/tasks
& u+ J) q  q5 I3 W# N2 p2996
7 v3 {. k4 s0 Z$ v3352
1 V3 Z% q. ~# M3 ?/ f3353   <-- stress 进程  m# l. h: v+ C0 [# V) j$ Y1 b
3354   <-- stress 进程
5 V* d, W- q1 q7 R# |复制代码
1 V* d* o: `( J( q3 f: s可以看出, A和B组中的 2个stress 进程的CPU使用率相加都是 100%,& I9 L3 o0 }: B- K  N1 }
% w! s% u+ l9 n, Y2 R5 q8 A, R
由于我测试的电脑是双核, top所看到的CPU最大使用率是 200%, 所以和预期一致, A和B组各占CPU总资源的 1/2
1 ?2 ~# f/ H* B
6 u6 L2 f6 P! B/ E 8 i7 \& R' H9 o1 W  [" |
+ E( E# L$ T" ^
实例2 - A group 占用整体CPU资源的 2/3, B group 占用整体CPU资源的 1/3
: O  e7 ~3 H5 N2 c6 v  r1 y5 q) i- q环境同 实例1, 不再重新挂载 cgroup 文件系统, 也不在重建 A 和 B/ _+ ^$ I0 U# X" J
A group 的 cpu.shares 文件不变, 值为 1024. I, i0 ?# |' d, k  w; j( I
B group 的 cpu.shares 文件中的值改为 512, 这样, 相当于B占用CPU总资源的 1/3 (因为 512 / (512+1024) = 1/3)( W1 L6 @# M  h1 U# s+ _
同实例1, 通过2个shell窗口, 分别是 A 和 B 的CPU使用率达到 100%, 然后通过 top 查看CPU使用情况8 P6 s1 m0 X# G5 Z3 r$ v

1 T0 z( D6 \/ c/ v# z5 I
  v" h! P( Z, m# |复制代码- ?$ A" `. U- {' H1 v) X5 Q6 i
# 在 B 中shell 窗口执行以下命令
- i+ _4 r$ P4 ~: d4 f" b0 {+ s% ocat B/cpu.shares
+ l4 U% ?) J2 W1024
( H9 ~9 `" M+ y- }* G& U7 y, Qecho 512 > B/cpu.shares 3 ]: B4 l# l" b
cat B/cpu.shares
1 c* L6 `& W' I' Q: d* [) x  d512
7 n! }/ P! y) t* G- `: p3 fstress -c 2& Y% |' L, o7 N5 S3 @# p
+ m; z8 A+ e: y' n1 E7 ~
# 在 A 中 shell 窗口执行以下命令
# z! q1 V8 p" F0 K5 k  J8 Y8 N3 vstress -c 2
. A' \4 l' r- A7 Z5 L9 c& L6 o" T8 j/ ], r! y1 W
# 在第3个 shell 窗口, 也就是 非A, 非B 的那个 shell 窗口, 用 top 查看cpu使用情况9 Z  f# P0 `: s! K6 a
top
, S) ~4 F5 @3 R% Ntop - 14:13:18 up 46 min,  3 users,  load average: 2.24, 1.92, 1.016 `& A# M) h1 W8 ~) c' ~
Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
$ I/ U+ V5 `$ M9 K- N9 U* A) C1 A%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
  h% t* e- w: ?# |3 w1 kKiB Mem:   1887872 total,   114744 used,  1773128 free,    10488 buffers5 A- ]1 _7 V" ]; y
KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached3 D# M4 r& u  h  j

6 D( h9 Y. e$ k  f PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                     
+ `# |7 T% y. R+ a3376 root      20   0  6524   88    0 R  66.6  0.0   0:06.29 stress                                                                                                                       
  K) x; m+ P1 j* t! Q, A. c3377 root      20   0  6524   88    0 R  66.6  0.0   0:06.30 stress                                                                                                                       4 f# R3 ]$ S* [
3373 root      20   0  6524   88    0 R  33.3  0.0   0:04.33 stress                                                                                                                       
: m& O5 s6 q7 Q! h8 I# K3374 root      20   0  6524   88    0 R  33.3  0.0   0:04.32 stress               , U, y+ p" v" j; A( M' @2 I

% L# D! Z$ L9 t* Y0 D  T# 查看这 4 个stress 进程是否分别属于 A 和 B+ I7 I. S3 a1 a' ]& u* N
cat /mnt/cgroup/A/tasks
; x. [8 b, d7 Z6 Y7 I1 N2945" W: M! s7 Q! p0 M' E3 g! O% h& r, K
33757 I' F0 r! f* F* M. G5 E
3376    <-- stress 进程. v3 G- |8 i6 i  @& I' ^
3377    <-- stress 进程
# N7 ]. p* }, R+ Z( s- e& W8 I+ @cat /mnt/cgroup/B/tasks
8 [* ?# S/ F: V! W- R- S29961 i2 ]( ?: B  P2 `/ J
3372
' |# G  a9 y) X2 N( \5 x3373    <-- stress 进程& d0 Z3 P( k# R: e
3374    <-- stress 进程
+ n& m# w) z+ r+ z4 w' r复制代码; h2 H( \. L! z* p8 X
很明显, A 组中的2个进程占用了CPU总量的 2/3 左右, B组中的2个进程占用了CPU总量的 1/3 左右.5 r2 Q0 q; B) ]  U9 Z" l$ H3 _, H! y4 _

/ _% Z' M- e* y7 o+ K' E2 M
( g; Y/ _+ a& e& V, }! f% L; \9 I2 g" l- d; K* {
实例3 - 物理CPU的控制
' T: Z) P' ]) Z; B4 ]; [上面的实例中, 虽然能够控制每个组的CPU的总体占用率, 但是不能控制某个组的进程固定在某个物理CPU上运行.
& I: a4 v! f* _) v* P- L( q1 M, v4 b
要想将 cgroup 绑定到某个固定的CPU上, 需要使用 cpuset 子系统.7 B0 R7 \0 b5 C& V8 y

6 m' U. r1 O( _/ S5 [% Z/ P: @( u5 Y首先, 查看系统是否支持 cpuset 子系统, 也就是看内核编译选项 CONFIG_CPUSETS 是否设为y5 k0 {  W3 R  V/ X( g
. q7 \8 P" a$ o' T% w4 p
cat /boot/config-`uname -r` | grep -i cpusets
1 F+ s4 R; a( c* ~8 `1 {/ T# XCONFIG_CPUSETS=y
" L/ _* g# c& a' e: d我的测试系统是支持的, 如果你的系统不支持, 就需要重新编译内核了.......- s" X7 `6 }. A7 g3 k
: O0 M6 R3 w6 h0 u" V- D
  Q' s: Z) E+ [; w: r( d" h* c! M

, s1 n4 L9 b# A7 b- @/ V然后, 用下面的例子演示将 A 和 B中的 stress 都指定到1个CPU上后的情况; V* c2 v0 K) {; ^
& s. X& x: ]$ X6 b9 N% `! q
卸载当前的 cgroup
6 M2 j6 n# f4 B( u+ ?2 E! d再次挂载 cgroup 文件系统, 并指定 -o cpuset
; B2 ~7 U& I+ L3 c, a/ n. S指定 A 的物理CPU为 0 (双核CPU的每个核编号分别是 CPU0, CPU1)
5 W& k; |- ]* R6 M3 N- y' Q5 G指定 B 的物理CPU也为 04 H9 m) J" H+ C% l4 b% f
重复 实例1 中的步骤, 观察发生的变化( T" u" m7 K7 g$ i
+ _; f8 \! ?3 U' L4 u3 v
# j2 p, T' l% ^. F) [6 ]  J
复制代码9 x1 u" G+ b) V! v
umount /mnt/cgroup" `! |- d5 q1 w8 |
mount -t cgroup -o cpuset cgroup /mnt/cgroup/- K! z" {! \5 P3 J1 d8 U
cd /mnt/cgroup1 Z7 a$ T2 k) |* w" y
ls -l
; [  D0 a' E" w5 I+ L: E2 \+ itotal 0! B6 t+ t7 a' W
-rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.clone_children) N. n3 h. [' L3 M7 R1 B, j
--w--w--w- 1 root root 0 Aug 28 14:39 cgroup.event_control
& q$ T. K& O" ]* `- {/ _: c-rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.procs, g8 U) E6 y+ x! \. c" [- w: S
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpu_exclusive
2 H& v5 a/ H6 A) [-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpus    <-- 这个就是设置关联物理CPU的文件
# R  ]' c7 Z% [  K-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_exclusive6 D& P6 B, l' [1 g4 a3 \+ V% X
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_hardwall
9 w7 d0 I' J2 i. S* m, l-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_migrate7 V) S; M* F4 B  F& \
-r--r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure) Z2 q- ~7 e' u- p. ~' O# U# j
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure_enabled
& r2 \. x5 g$ @-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_page
3 e2 v7 J# K$ X' z* G" e+ r-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_slab
# b3 D% X$ f8 c, e5 U-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mems
6 }* a! D7 O/ U+ z! R' Z1 B+ n-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_load_balance- i5 p! C" M5 p% S/ C3 `; P
-rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_relax_domain_level4 w$ w4 Y8 p7 K+ [
-rw-r--r-- 1 root root 0 Aug 28 14:39 notify_on_release, Q0 l, d4 V& T* _, p! T
-rw-r--r-- 1 root root 0 Aug 28 14:39 release_agent
& P* w; Z# k* d. o-rw-r--r-- 1 root root 0 Aug 28 14:39 tasks2 W$ K) y0 i1 G$ N( t, p

1 b5 n" K* \* N' S( n! ?# 创建子cgroup A 和 B
  t; M7 \4 \7 d4 amkdir {A,B}8 h9 ?( y$ e' C" }8 G
cat A/cpuset.cpus   - |2 Y( q3 p/ x. c( N) J
         <--  默认是空的* V/ W1 m5 _8 f# X/ _+ @6 b$ Z
echo 0 > A/cpuset.cpus
( r8 b" X" T' j- B1 fcat A/cpuset.cpus % H0 Y2 T, _2 x% b7 x( H6 N+ W
0
' G1 s. a' J7 ^1 }% fecho 0 > B/cpuset.cpus   # 同样, 设置B组也绑定到CPU0( K7 `8 T) t; H3 G( t0 q1 d
# 当前Shell加入到 A组9 x  `; E6 h. T( B# d$ f+ w0 P
echo $$ > /mnt/cgroup/A/tasks
& z- w) Q3 C9 k0 D-bash: echo: write error: No space left on device2 L+ G2 p$ X4 n4 _
复制代码  q# K/ F5 W. S9 R
1 e5 c) S! z' Y9 v, ?) g
+ C" d9 ], p4 G/ z3 \- f2 I
如果出现上述错误, 只需要再设置 /mnt/cgroup/A/cpuset.mems 即可. (参考: http://serverfault.com/questions/579555/cgroup-no-space-left-on-device)
: p; o0 V% ^0 p* o/ }4 \3 S" o) ?( H8 j  C! `- u( \* T
复制代码% u# b4 @4 y7 |$ b  W) z
# 同时设置 A 的 cpuset.cpus 和 cpuset.mems5 e- |3 K& f9 r  q8 R$ E8 i) s
echo 0 > A/cpuset.cpus8 M1 `( k( C) T. k* ~
echo 0 > A/cpuset.mems: X4 @/ g2 ]2 H
# B组也同样设置7 ?+ V$ _- p' u! d0 B
echo 0 > B/cpuset.cpus/ L+ b0 U. b2 K7 e+ F
echo 0 > B/cpuset.mems
; j5 f0 Q- j  G8 ?  q
* p9 ^/ J% @/ O. {3 h# 将当前 shell 加入到 A组+ Q  b' y/ J7 H1 x, W
echo $$ > /mnt/cgroup/A/tasks   <-- 设置过 cpuset.mems 后, 就没有出错了
4 J# x# O  J9 b% X; k; dstress -c 25 c7 A# P. p. w! ^) m8 h: e0 y
! D& z& Y/ k) `( D( ^
# 再打开一个Shell窗口, 并加入到 B组
( L, o/ _# j* e' q1 I9 Cecho $$ > /mnt/cgroup/B/tasks3 q( X5 \' ~5 {( U" \4 W& s
stress -c 2: e* b! f5 k- _

& B7 q  I" C7 L# x" n# 再打开第3个 shell 窗口, 用top命令查看CPU使用情况+ O% k" Y: X! ?2 R' z
top9 p: W/ |: c  C6 v# c
top - 15:13:29 up  1:46,  3 users,  load average: 1.01, 0.24, 0.12
  R$ F6 X: V! |1 c; tTasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie" M* h2 I4 p- y, ]
%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 st9 f7 r$ E5 \8 F* p8 D; Y
KiB Mem:   1887872 total,   117216 used,  1770656 free,    11144 buffers2 ?" {( E/ t8 o9 m, T$ u& ]1 b
KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
6 ?1 m" d* [' v  o8 r" U( o; ^8 w4 [
PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      " {6 D. A" ]( ]' N2 f- g" V
3830 root      20   0  6524   92    0 R  25.0  0.0   0:04.96 stress                                                                                                                       
* A* K: k! z  N" x" _! L& t3831 root      20   0  6524   92    0 R  25.0  0.0   0:04.97 stress                                                                                                                       % T. ?4 P* D! r/ a
3834 root      20   0  6524   92    0 R  25.0  0.0   0:03.56 stress                                                                                                                       + E# a  ?' {( C4 N
3833 root      20   0  6524   92    0 R  24.6  0.0   0:03.56 stress. [( t2 \* F: n: b
复制代码
- W4 x7 g+ ^- k- |: I+ g0 d# O从上面的结果可以看出, 虽然 stress 命令指定了 -c 2(意思是在2个CPU上运行), 但是由于A和B都只绑定了CPU0,
5 x7 @) j9 W8 {3 T4 o% P& \8 X8 a( m; i, Y. O
所以虽然是双核的机器, 它们所占用的CPU总量却只有 100%, 而不是实例1 中的 200%.  I* b* D) u4 s) b

& H" P8 C! h- V
$ c1 t$ g# g: g/ T1 K; ~+ v6 V1 O
1 V% d' ]8 {1 h( o如果将B组的物理CPU绑定到CPU1, 那么应该所有 stress 的进程都占用 50%, CPU资源的总量变为 200%.# d! K6 Y% W1 t

0 m0 E+ A  u. `% W& ?下面将B组的物理CPU绑定为CPU1, 看看结果是否和我们的预期一样.$ B6 v$ _8 e# g& U6 V. C

4 ^' R% I" \* W! i3 S4 |复制代码% W# F& u6 d) M! w0 \4 p2 c( _
# 在 B组的 shell 窗口中执行以下命令
. p$ e% H; D) O% g) T6 |* }echo 1 > /mnt/cgroup/B/cpuset.cpus
% n  a$ e! G# z  }% M6 j3 q2 Rcat /mnt/cgroup/B/cpuset.cpus5 F5 i& C) F. q/ k8 B' {5 ?
1
, @# c; R' `  E7 b- Y) Sstress -c 2
0 W( I0 z: l) b5 R+ ^
& O# a( q" Q! h, \0 k. b5 e: q0 b# 在 A组的 shell 窗口中执行以下命令( x9 ]8 M/ J4 \3 V* m3 N& T
stress -c 2
, e5 z, ]  D) D) A
1 v$ d7 e6 [) S* n' W/ a# 在第3个shell窗口中用top命令查看执行结果. \$ R2 m# {3 t1 w" [# e' _9 B
top( U1 N! s5 t: G& C
top - 15:20:07 up  1:53,  3 users,  load average: 0.38, 0.83, 0.56
* |( }) p" S" KTasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie; B9 H0 p8 H; ?" Y  r% }5 P$ a# S
%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; _  B: }$ Y8 I8 T# |
KiB Mem:   1887872 total,   117340 used,  1770532 free,    11168 buffers7 v6 r  E2 h# R. P* J2 `
KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
' U# d( L3 q& ~, ?, L9 @
  _. _5 Y1 Z) v. l; L4 r' W  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                     
0 Z+ D* l; f6 Q" b  a3 r 3854 root      20   0  6524   88    0 R  49.9  0.0   0:03.76 stress                                                                                                                       
' ]3 V) g/ `+ ?9 i8 D 3857 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       0 W8 i+ p3 x7 B' \% \
3858 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       0 h5 ]" |! }7 M: O
3855 root      20   0  6524   88    0 R  49.6  0.0   0:03.76 stress/ q/ r5 B' l2 A+ y
复制代码
# D& n: \3 m8 J6 h/ ]" o, z0 G  n果然, 和预期一致. A组中的 stress 和 B组中的 stress 在各自的物理CPU上都占用了 100% 左右的CPU使用率.
# F- c; _5 y5 }+ I1 Y+ t
' {& m6 H5 v- {" w. g: E6 R, _ : t- Y; a7 j; p2 u7 @
; Z# X4 u2 Q6 q2 T/ r
实例4 - cgroup 对使用的内存的控制8 L! n9 M; [! _0 g
cgroup 对内存的控制也很简单, 只要挂载cgroup时, 指定 -o memory
% L5 M: O6 C: a5 A+ g2 ?& z
0 l. c$ Y1 i. N( }' x# 首先之前挂载的 cpuset 子系统
) F( B  `1 e+ h' v4 O( _umount /mnt/cgroup# Q3 p; y" M4 j

- ~$ @- X0 k  k% C4 M. p# 挂载cgroup 文件系统, 指定 -o memeory' r+ i1 \* C+ `7 x9 ^
mount -o memory -t cgroup mEMCg /mnt/cgroup/  h5 u* w6 w  l5 f4 L1 ~- ?
mount: special device memcg does not exist+ Y% N* `. N7 w& V8 v

) d( q$ K2 O4 M% D
& `& s  {# o* M1 A( h8 q出现以上错误的原因可能是因为debian系统中, 默认没有启动 cgroup 的memory子系统. 可以通过以下方法确认:/ z8 y, n9 k! _6 T# j$ Z

4 `7 k' J7 g: o/ g复制代码
' u' W/ O* n  M8 G5 \cat /proc/cgroups
- V7 V7 A. t( O! H+ ~#subsys_name    hierarchy    num_cgroups    enabled: B% W  Y" z: W) F* @. R
cpuset    0    1    1& ]; o1 z. p2 K
cpu    0    1    1
+ A6 u0 J# a$ q1 Y: mcpuacct    0    1    1
7 ]7 ^* e  I% }, o( a& J; b  pmemory    1    1    0              <-- 这里的 enabled 是 09 Q# y; J0 k8 n  F& X9 e3 g
devices    0    1    1
" {6 X/ J2 \- [# O9 [$ zfreezer    0    1    1
& W. k  L& M* {) `! A5 }& a* Y+ G! Lnet_cls    0    1    1$ I" w) h+ Q/ v4 a8 F
blkio    0    1    1
$ u" U: u4 y, \9 Y$ [5 LpeRF_event    0    1    16 @; `6 E, A! Z
复制代码
( Y; B4 C+ ^7 u+ }: J9 w
9 A7 i8 Q2 X, g3 W5 g3 S  J7 \5 e0 D0 y% d" g7 r
为了默认启用memory子系统, 可以设置 grub选项
( p/ P' t2 T# _& }8 L; c0 d2 g5 \: p8 O- x" b7 w
vim /etc/default/grub
+ I$ n6 E+ Q! U3 |- g( l/ x# 修改 GRUB_CMDLINE_LINUX=""  ==> GRUB_CMDLINE_LINUX="cgroup_enable=memory"8 K, d' E: p1 \4 Y3 d7 S
# 保存后, 更新grub.cfg
5 A# R0 o# r) ~" R3 Hupdate-grub& ^/ v. m/ @# X
reboot' [6 J* C; s  ~. l. y8 S" @( b& @

" K9 |1 p; M3 A! Q6 ~, ~0 x0 e; u2 Q2 |) w) M+ k
重启之后, 发现 /proc/cgroups 中的memory已经 enabled, 并且也可以挂载 memcg了
+ m% }- |: k$ y* N  h2 P! F2 v# V% L& o4 R+ c/ k) }
复制代码3 T; s' J. o! o% ^2 F" \7 w1 V
cat /proc/cgroups / I  o$ {  v$ D: W. A
#subsys_name    hierarchy    num_cgroups    enabled8 ~! B/ J4 o- G- o
cpuset    0    1    1
! V4 U$ r- s! n/ ~5 @; m, Hcpu    0    1    1
4 m7 _/ J, j. Hcpuacct    0    1    1+ J0 e+ O' |7 L$ V
memory    1    1    17 z2 j, [) ^  V8 d3 G- o% d
devices    0    1    18 _% W5 t$ q8 v; F0 S( b
freezer    0    1    1
: R  J; U' r1 N. k( Y3 i. wnet_cls    0    1    1
! u& \9 ?6 N0 x" |# bblkio    0    1    1
# B) Z2 J7 C+ m+ d% ?- Yperf_event    0    1    1
$ @+ V+ F4 B: X! M) U& K
  @* n6 _- N  I7 d  R/ Q# 挂载cgroup 的memory子系统
4 s3 E3 `: T# _( _) Bmount -t cgroup -o memory memcg /mnt/cgroup
0 H. b. B  O( D! l" c! r2 cls -l /mnt/cgroup/   <-- 可以看到有很多 memory 相关的配置
' Z3 t$ [9 A, f. Ltotal 0
  V1 m8 `/ h* ]% r- r, I) @-rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.clone_children
; y* l2 p( N! I8 ]--w--w--w- 1 root root 0 Aug 28 15:54 cgroup.event_control% I& r7 g/ e$ g9 \
-rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.procs
7 @1 b% @/ P5 W. n0 m/ H# V-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.failcnt7 v/ k+ K+ ]' w
--w------- 1 root root 0 Aug 28 15:54 memory.force_empty
# w- a& D+ {/ w1 D; e-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.limit_in_bytes   <-- 限制内存使用的配置文件; p. K9 _. ~6 q# X
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.max_usage_in_bytes( K( C# a+ P* }1 f
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.move_charge_at_immigrate
0 |& o" U* U8 k1 L0 t-r--r--r-- 1 root root 0 Aug 28 15:54 memory.numa_stat1 @0 ~# U/ v( @- e. K
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.oom_control
) d) ^! d4 ]: Y/ d-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.soft_limit_in_bytes
- _- R" `6 \" h& l% `, Z-r--r--r-- 1 root root 0 Aug 28 15:54 memory.stat% h0 o. m( H* e2 \9 i
-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.swappiness
4 y# H9 [5 r( u4 X-r--r--r-- 1 root root 0 Aug 28 15:54 memory.usage_in_bytes
3 o4 t1 E) t) H" H9 z) V-rw-r--r-- 1 root root 0 Aug 28 15:54 memory.use_hierarchy
( Q/ P! }: {/ B8 ?: C+ @! I-rw-r--r-- 1 root root 0 Aug 28 15:54 notify_on_release2 k* Y! G2 u5 i6 Y  A! g% |
-rw-r--r-- 1 root root 0 Aug 28 15:54 release_agent
# U4 ^, z" i- S5 C8 \-rw-r--r-- 1 root root 0 Aug 28 15:54 tasks7 \+ t/ L. z) ^$ G- ^
复制代码
7 e$ U) L4 ]: T# y8 D" h % x4 J" |, M- x  i% Y  R

4 _; v9 k; T* U/ M& ?开始实验:7 A+ I. }4 w0 K# Z# I

0 E% C5 u+ w4 Y; V- E0 R, Z' G  V重启系统 (为了保证内存的干净)
3 k9 Y/ ?( N% H8 v* \% f挂载 memcg
  l$ _7 T+ G# W# B$ q$ T在挂载的 /mnt/cgroup 中创建 组A( I8 S: o$ k( {* ]
将当前shell 加入到 组A
8 ]9 e) c# C. L* b' S不限制组A的内存, 压缩内核源码包, 并观察压缩前后内存的变化
( ^% F4 C0 ~+ V2 h" G$ s" l2 A重复步骤 1 ~ 4- |6 C( [1 m+ v) U* |& b5 h
限制组A的内存为 10MB, 再次压缩内核源码包, 并观察压缩前后内存的变化
1 y  Z6 M5 E! i  B9 T 6 m$ Z* d' U: M3 \

  Y: b; Y+ t3 V$ H  T/ Y. h复制代码& r+ w! V5 Q" |6 L3 F2 b) i. R
# 重启系统5 c5 q9 k( X5 ~( A2 t  M
reboot- G( W4 k/ r% L. m7 @" j

/ p* y7 ]& S, g  z3 S4 W# 挂载 memcg; x, B' M* v1 E- H
mount -t cgroup -o memory memcg /mnt/cgroup
+ j& E: O, e* F# O1 v' \3 b/ S% I0 M. E7 h2 z8 P! X( b$ p
# 创建 组A
" |4 m5 n+ q& c$ M  }% y- Gmkdir /mnt/cgroup/A3 P/ W- q! n$ `9 U

# d& p" ]3 x' v% p7 o9 c  n# 将当前 shell 加入到组A
0 V! z8 s) K* Y: }$ V6 Decho $$ > /mnt/cgroup/A/tasks
8 `/ |2 ^& Q0 l7 Y) |* @8 W, C/ \' M  Q/ E3 L6 c4 I
# 测试不限制内存时, 内存的使用情况, 这里不用linux源码也可以, 但最好用个大点的文件夹来压缩, 以便更容易看出内存的变化.$ R8 k) _0 h! d4 A1 |# C" l6 U
free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
; F1 A; C2 D5 ~             total       used       free     shared    buffers     cached
. A( s# F. l0 S. [2 uMem:          1843        122       1721          0          9         433 h# a: a4 Z; M( I: w
-/+ buffers/cache:         68       1774
" B1 w$ P# `, p& USwap:         3888          0       3888
' B; G( v, {6 [             total       used       free     shared    buffers     cached
$ ^" \0 l. f8 F( mMem:          1843       1744         99          0         26       1614
* E' l8 s) l: v+ |7 _( k-/+ buffers/cache:        104       17392 v/ r% X5 i. z# H# W7 Y7 m
Swap:         3888          0       3888% v0 f- g1 y+ o- g% x

1 z' l0 |' N- t# L+ ^% q2 h# 重启系统: l8 }. w/ D* W# L4 o
reboot
: ^) N" A. u5 P+ y+ ^. ~& c5 j. r1 z
; K& n2 n* w" |9 \# 挂载 memcg/ T! j* C" o8 s9 U7 w9 F
mount -t cgroup -o memory memcg /mnt/cgroup' v4 P* j* @9 g: |2 j

) X/ W5 ?+ [8 o1 b" o$ y# 创建 组A5 D' b0 `) N) q
mkdir /mnt/cgroup/A
) ~! L& e+ n7 s4 A. V+ T% t5 p  b5 Q0 O7 i3 r' s. @
# 将当前 shell 加入到组A
" L8 \9 R0 Y4 Pecho $$ > /mnt/cgroup/A/tasks+ A1 t/ i5 K& F  N

2 l# _0 j% Z/ q# 限制 组A 的内存使用量最大为 10MB( m: u4 f+ ?" D
echo 10M > /mnt/cgroup/A/memory.limit_in_bytes0 G9 a! g3 q) f+ U. F

8 S: b# \8 V. ^: e2 w; [! b' B# 测试限制内存为 10MB 时, 内存的使用情况.
; v( ~- |5 R! S4 Jrm -rf linux-source-3.2.tar.gz% e) l" T3 h2 Y2 }
free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;3 j# ]$ H$ l5 u4 ]0 e& G
             total       used       free     shared    buffers     cached7 T# Z5 V# c8 q3 x1 f
Mem:          1843        122       1721          0         10         430 n( k4 o( C8 C, {1 x8 x
-/+ buffers/cache:         68       1774; W* \& ^3 I6 h6 g/ S8 S
Swap:         3888          0       3888
  W- a* X, Q: Y6 |" a             total       used       free     shared    buffers     cached
& t8 c1 S) C+ d! BMem:          1843        194       1649          0         14         48
4 [3 H. a/ A/ M3 n' t! X5 T-/+ buffers/cache:        131       17127 _1 H  F5 J: |* F$ M# T
Swap:         3888          0       3888  c( A3 `% l! V0 m4 @4 u
复制代码; p# c( G( D7 x' ?% ]
从上面的结果可以看出限制内存是起了作用的.
9 l% ]$ S/ M2 H- A* n' F& v4 x1 n7 l  i
不限制内存时, tar 压缩前后 buffer + cache 内存从 (9MB + 43MB) ==> (26MB + 1614MB)  增大了 1588MB) @) P5 e/ |2 f5 o

- G* R0 C  B9 f9 g! q( ?/ R$ ~限制内存后, tar 压缩前后 buffer + cache 内存从 (10MB + 43MB) ==> (14MB + 48MB)  增大了 9MB
4 A" ?$ ?3 h2 d5 Q$ o" I8 D, ~6 x* _/ v- e0 A: |3 C- N

/ y: Z# s; a' F- R. v/ Z! e, ^4 j/ Q$ u; l0 O8 }8 Y$ C! ^2 y
总结7 ]9 J* {1 z7 {- s& _3 R" j% v
简单的实验就发现 cgroup 如此强大的控制能力(而且配置也很简单), 这也就难怪LXC等容器技术能如此强大, 如此流行.$ i+ s3 S3 L, B

& N+ E3 E6 ?2 B3 v/ a9 C& V5 [cgroup 的配置文件很多, 上面的实例中只简单使用了其中的几个配置文件, 如果想深入了解 cgroup, 更好的利用cgroup的话,- m) ?4 K1 W  h/ M" ~! J' Z
2 e1 n6 }* y9 }9 h; v
还得找个介绍cgroup配置文件的文档来研究一下, 这篇博客提供的内容还远远不够.
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-6-27 07:32 , Processed in 0.093750 second(s), 23 queries , Gzip On.

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

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

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