• Linux资源控制-CPU和内存【转】


    转自:http://www.cnblogs.com/wang_yb/p/3942208.html

    主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法。

    CPU资源控制

    每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的.

    Linux系统中有多种调度策略, 各种调度策略有其适用的场景, 也很难说哪种调度策略是最优的.

    Linux的调度策略可以参见代码: include/linux/sched.h

    复制代码
    /*
     * Scheduling policies
     */
    #define SCHED_NORMAL        0
    #define SCHED_FIFO        1
    #define SCHED_RR        2
    #define SCHED_BATCH        3
    /* SCHED_ISO: reserved but not implemented yet */
    #define SCHED_IDLE        5
    /* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */
    #define SCHED_RESET_ON_FORK     0x40000000
    复制代码

    Linux 系统也提供了修改调度策略的命令和系统调用接口.

    调用接口请查询相关文档, 这里主要介绍一下修改调度策略的命令 - chrt.

    复制代码
    # 在一个终端中执行
    sleep 1000
    # 打开另一个终端
    ps -ef | grep sleep  # 找出 sleep 1000 的pid, 这里假设是 1234
    chrt -p 1234         # 可以查看 pid=1234 的进程的 调度策略, 输入如下:
          pid 1234's current scheduling policy: SCHED_OTHER
          pid 1234's current scheduling priority: 0
    
    chrt -p -f 10 1234   # 修改调度策略为 SCHED_FIFO, 并且优先级为10
    chrt -p 1234         # 再次查看调度策略
          pid 1234's current scheduling policy: SCHED_FIFO
          pid 1234's current scheduling priority: 10
    复制代码

    补充:

    1. chrt 也可以直接指定一条命令, 并设置这条命令的优先级的调度策略, 具体查看 chrt --help
    2. 查看一个进程的调度策略, 除了使用 chrt 命令之外, 还可以 cat /proc/<PID>/sched

    实时进程的CPU控制

    所谓的实时进程, 也就是那些对响应时间要求比较高的进程.

    这类进程需要在限定的时间内处理用户的请求, 因此, 在限定的这段时间内, 需要占用所有CPU资源, 并且不能被其它进程打断.

    在这种情况下, 如果实时进程中出现了类似死循环之类的情况, 就会导致整个系统无响应.

    因为实时进程的CPU优先级高, 并且未处理完之前是不会释放CPU资源的.

    所以, 内核中需要有一种方式来限制实时进程的CPU资源占用.

    系统整体设置

    1. 获取当前系统的设置

    sysctl -n kernel.sched_rt_period_us   # 实时进程调度的单位CPU时间 1 秒
    1000000
    sysctl -n kernel.sched_rt_runtime_us  # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒
    950000

    这个设置说明实时进程在运行时并不是完全占用CPU的, 每1秒中有0.05秒的时间可以给其它进程运行.

    这样既不会对实时进程的响应时间造成太大的影响, 也避免了实时进程卡住时导致整个系统无响应.

    2. 设置实时进程占用CPU时间

    上面的默认设置中, 实时进程占用 95% 的CPU时间. 如果觉得占用的太多或太少, 都是可以调整的.比如:

    sysctl -w kernel.sched_rt_runtime_us=900000    # 设置实时进程每1秒中只占0.9秒的CPU时间
    kernel.sched_rt_runtime_us = 900000
    sysctl -n kernel.sched_rt_runtime_us 
    900000

    cgroup 中的设置

    整体设置是针对整个系统的, 我们也可以通过 cgroup 来对一组进程的CPU资源进行控制.

    如果想在 cgroup 中对 sched_rt_period_us 和 sched_rt_runtime_us 进行控制, 需要内核编译选项 CONFIG_RT_GROUP_SCHED=y

    查看当前系统的内核编译选项方法如下: (debian 7.6 系统)

    cat /boot/config-`uname -r`

    查看 CONFIG_RT_GROUP_SCHED 是否启用

    cat /boot/config-`uname -r` | grep -i rt_group
    # CONFIG_RT_GROUP_SCHED is not set

    debian 7.6 默认没有启动这个选项, 所以挂载cgroup之后, 没有设置 sched_rt_period_us 和 sched_rt_runtime_us 的文件

    复制代码
    mkdir /mnt/cgroup
    mount -t cgroup cgroup /mnt/cgroup/
    cd /mnt/cgroup/
    ls -l
    total 0
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_merged
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_queued
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_bytes
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_serviced
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_service_time
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.io_wait_time
    --w------- 1 root root 0 Aug 28 09:06 blkio.reset_stats
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.sectors
    -r--r--r-- 1 root root 0 Aug 28 09:06 blkio.time
    -rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight
    -rw-r--r-- 1 root root 0 Aug 28 09:06 blkio.weight_device
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 09:06 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cgroup.procs
    -r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.stat
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage
    -r--r--r-- 1 root root 0 Aug 28 09:06 cpuacct.usage_percpu
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.cpus
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 09:06 cpu.shares
    --w------- 1 root root 0 Aug 28 09:06 devices.allow
    --w------- 1 root root 0 Aug 28 09:06 devices.deny
    -r--r--r-- 1 root root 0 Aug 28 09:06 devices.list
    -rw-r--r-- 1 root root 0 Aug 28 09:06 net_cls.classid
    -rw-r--r-- 1 root root 0 Aug 28 09:06 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 09:06 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 09:06 tasks
    复制代码

    果然, 只有cpu.share, 没有 cpu.sched_rt_period_us 和 cpu.sched_rt_runtime_us

    没办法, 重新编译内核, 编译内核的具体方法参见:  编译Linux内核

    为了节约时间, 我们用 make localmodconfig 来创建 .config 文件, 然后修改其中的 CONFIG_RT_GROUP_SCHED=y

    下载源码等等参见: 编译Linux内核, 主要步骤如下:

    复制代码
    cd /path/to/linux-source-3.2
    make localmodconfig
    vim .config   # 设置 CONFIG_RT_GROUP_SCHED=y 并保存
    make
    make modules_install
    make install
    reboot      # 重启之前看看 /boot/grub/grub.cfg 中, 默认启动的是不是新安装的内核
    复制代码
     

    启动到新内核, 再次查看内核选项 CONFIG_RT_GROUP_SCHED 是否启用

    cat /boot/config-`uname -r` | grep -i rt_group
    CONFIG_RT_GROUP_SCHED=y       # 已启用

    再次挂载 cgroup 文件系统, 发现多了2个配置文件, cpu.rt_period_us 和 cpu.rt_runtime_us

    复制代码
    mount -t cgroup cgroup /mnt/cgroup/
    cd /mnt/cgroup/
    ls -l
    total 0
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_merged
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_queued
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_bytes
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_serviced
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_service_time
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.io_wait_time
    --w------- 1 root root 0 Aug 28 09:53 blkio.reset_stats
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.sectors
    -r--r--r-- 1 root root 0 Aug 28 09:53 blkio.time
    -rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight
    -rw-r--r-- 1 root root 0 Aug 28 09:53 blkio.weight_device
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 09:53 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cgroup.procs
    -r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.stat
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage
    -r--r--r-- 1 root root 0 Aug 28 09:53 cpuacct.usage_percpu
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_period_us
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.rt_runtime_us
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.cpus
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 09:53 cpu.shares
    --w------- 1 root root 0 Aug 28 09:53 devices.allow
    --w------- 1 root root 0 Aug 28 09:53 devices.deny
    -r--r--r-- 1 root root 0 Aug 28 09:53 devices.list
    -rw-r--r-- 1 root root 0 Aug 28 09:53 net_cls.classid
    -rw-r--r-- 1 root root 0 Aug 28 09:53 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 09:53 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 09:53 tasks
    
    cat cpu.rt_period_us 
    1000000
    cat cpu.rt_runtime_us 
    950000
    复制代码

    通过配置 cpu.rt_period_us 和 cpu.rt_runtime_us 就可以对 cgroup 中的进程组中的实时进程进行 CPU使用时间的控制.

    资源控制实例

    上面主要介绍资源的一些理论基础, 下面通过一些实例演示如果通过 cgroup 来控制进程所使用的 CPU和内存 资源.

    Linux对CPU 和 内存的控制有对应的 cgroup 子系统 cpuset 和 memory

    实例: cgroup 中对其中 *子cgroup* 的CPU资源控制

    对各个 *子cgroup* 的CPU占用率进行控制主要依靠每个 *子cgroup* 的 cpu.shares 文件

    直接用实验过程来说话, 其中加入了一些注释.

    # 安装需要的软件
    apt-get install stress     # 让CPU达到 100% 的压力工具
    apt-get install sysstat    # 查看系统CPU, 内存, 磁盘, 网络等资源使用情况的工具
    实例1 - 默认情况, A 和 B 各占CPU总资源的 1/2
    1. 挂载 cgroup 文件系统 (注意加上 -o cpu 的选项)
    2. 在 cgroup中创建 2个子cgroup A 和 B
    3. 默认情况下, cgroup A 和 cgroup B 中的 cpu.shares 中的数值都是 1024
    4. 在 A 和 B 中用 stress 工具使其 CPU占用率达到 100%
    5. top 命令查看 A 和 B 中进程分别占用的 CPU (应该都是 50%)
    复制代码
    # 挂载 cgroup 文件系统
    mount -t cgroup -o cpu cgroup /mnt/cgroup/
    cd /mnt/cgroup
    ls -l
    total 0
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_merged
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_queued
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_bytes
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_serviced
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_service_time
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.io_wait_time
    --w------- 1 root root 0 Aug 28 11:29 blkio.reset_stats
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.sectors
    -r--r--r-- 1 root root 0 Aug 28 11:29 blkio.time
    -rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight
    -rw-r--r-- 1 root root 0 Aug 28 11:29 blkio.weight_device
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 11:29 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cgroup.procs
    -r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.stat
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage
    -r--r--r-- 1 root root 0 Aug 28 11:29 cpuacct.usage_percpu
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.cpus
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 11:29 cpu.shares
    --w------- 1 root root 0 Aug 28 11:29 devices.allow
    --w------- 1 root root 0 Aug 28 11:29 devices.deny
    -r--r--r-- 1 root root 0 Aug 28 11:29 devices.list
    -rw-r--r-- 1 root root 0 Aug 28 11:29 net_cls.classid
    -rw-r--r-- 1 root root 0 Aug 28 11:29 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 11:29 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 11:29 tasks
    
    # 创建 子cgroup A 和 B
    mkdir {A,B}
    cat A/cpu.shares 
    1024
    cat B/cpu.shares 
    1024
    
    # 在 A 和 B 中分别通过 stress 工具使其CPU使用率达到 100%
    echo $$ > A/tasks  # 将当前的 SHELL 加入到 cgroup A中
    stress -c 2    # 这里-c 2 是因为测试机器是双核, 要在2个核上都产生 100% 的CPU 占用率
    # 另外打开一个 shell 窗口, 并将这个shell 加入到 cgroup B中
    echo $$ > B/tasks  # 将当前的 SHELL 加入到 cgroup B中
    stress -c 2    # 在2个核上都产生 100% 的CPU 占用率
    # 再打开一个 shell 窗口, 用top命令查看 CPU占用情况
    top
    top - 14:10:32 up 43 min,  3 users,  load average: 2.31, 1.24, 0.62
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %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
    KiB Mem:   1887872 total,   114744 used,  1773128 free,    10472 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
    
     PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      
    3350 root      20   0  6524   92    0 R  49.9  0.0   0:08.73 stress                                                                                                                       
    3351 root      20   0  6524   92    0 R  49.9  0.0   0:08.67 stress                                                                                                                       
    3353 root      20   0  6524   92    0 R  49.9  0.0   0:07.35 stress                                                                                                                       
    3354 root      20   0  6524   92    0 R  49.9  0.0   0:07.36 stress                    
    
    # 查看这 4 个stress 进程是否分别属于 A 和 B
    cat /mnt/cgroup/A/tasks 
    2945
    3349
    3350   <-- stress 进程
    3351   <-- stress 进程
    cat /mnt/cgroup/B/tasks 
    2996
    3352
    3353   <-- stress 进程
    3354   <-- stress 进程
    复制代码

    可以看出, A和B组中的 2个stress 进程的CPU使用率相加都是 100%,

    由于我测试的电脑是双核, top所看到的CPU最大使用率是 200%, 所以和预期一致, A和B组各占CPU总资源的 1/2

    实例2 - A group 占用整体CPU资源的 2/3, B group 占用整体CPU资源的 1/3
    1. 环境同 实例1, 不再重新挂载 cgroup 文件系统, 也不在重建 A 和 B
    2. A group 的 cpu.shares 文件不变, 值为 1024
    3. B group 的 cpu.shares 文件中的值改为 512, 这样, 相当于B占用CPU总资源的 1/3 (因为 512 / (512+1024) = 1/3)
    4. 同实例1, 通过2个shell窗口, 分别是 A 和 B 的CPU使用率达到 100%, 然后通过 top 查看CPU使用情况
    复制代码
    # 在 B 中shell 窗口执行以下命令
    cat B/cpu.shares 
    1024
    echo 512 > B/cpu.shares 
    cat B/cpu.shares 
    512
    stress -c 2
    
    # 在 A 中 shell 窗口执行以下命令
    stress -c 2
    
    # 在第3个 shell 窗口, 也就是 非A, 非B 的那个 shell 窗口, 用 top 查看cpu使用情况
    top
    top - 14:13:18 up 46 min,  3 users,  load average: 2.24, 1.92, 1.01
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %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
    KiB Mem:   1887872 total,   114744 used,  1773128 free,    10488 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    45068 cached
    
     PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      
    3376 root      20   0  6524   88    0 R  66.6  0.0   0:06.29 stress                                                                                                                       
    3377 root      20   0  6524   88    0 R  66.6  0.0   0:06.30 stress                                                                                                                       
    3373 root      20   0  6524   88    0 R  33.3  0.0   0:04.33 stress                                                                                                                       
    3374 root      20   0  6524   88    0 R  33.3  0.0   0:04.32 stress               
    
    # 查看这 4 个stress 进程是否分别属于 A 和 B
    cat /mnt/cgroup/A/tasks 
    2945
    3375
    3376    <-- stress 进程
    3377    <-- stress 进程
    cat /mnt/cgroup/B/tasks 
    2996
    3372
    3373    <-- stress 进程
    3374    <-- stress 进程
    复制代码

    很明显, A 组中的2个进程占用了CPU总量的 2/3 左右, B组中的2个进程占用了CPU总量的 1/3 左右.

    实例3 - 物理CPU的控制

    上面的实例中, 虽然能够控制每个组的CPU的总体占用率, 但是不能控制某个组的进程固定在某个物理CPU上运行.

    要想将 cgroup 绑定到某个固定的CPU上, 需要使用 cpuset 子系统.

    首先, 查看系统是否支持 cpuset 子系统, 也就是看内核编译选项 CONFIG_CPUSETS 是否设为y

    cat /boot/config-`uname -r` | grep -i cpusets
    CONFIG_CPUSETS=y

    我的测试系统是支持的, 如果你的系统不支持, 就需要重新编译内核了.......

    然后, 用下面的例子演示将 A 和 B中的 stress 都指定到1个CPU上后的情况

    1. 卸载当前的 cgroup
    2. 再次挂载 cgroup 文件系统, 并指定 -o cpuset
    3. 指定 A 的物理CPU为 0 (双核CPU的每个核编号分别是 CPU0, CPU1)
    4. 指定 B 的物理CPU也为 0
    5. 重复 实例1 中的步骤, 观察发生的变化
    复制代码
    umount /mnt/cgroup
    mount -t cgroup -o cpuset cgroup /mnt/cgroup/
    cd /mnt/cgroup
    ls -l
    total 0
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 14:39 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cgroup.procs
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpu_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.cpus    <-- 这个就是设置关联物理CPU的文件
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_exclusive
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mem_hardwall
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_migrate
    -r--r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_pressure_enabled
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_page
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.memory_spread_slab
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.mems
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_load_balance
    -rw-r--r-- 1 root root 0 Aug 28 14:39 cpuset.sched_relax_domain_level
    -rw-r--r-- 1 root root 0 Aug 28 14:39 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 14:39 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 14:39 tasks
    
    # 创建子cgroup A 和 B
    mkdir {A,B}
    cat A/cpuset.cpus   
             <--  默认是空的
    echo 0 > A/cpuset.cpus
    cat A/cpuset.cpus 
    0
    echo 0 > B/cpuset.cpus   # 同样, 设置B组也绑定到CPU0
    # 当前Shell加入到 A组
    echo $$ > /mnt/cgroup/A/tasks 
    -bash: echo: write error: No space left on device
    复制代码

    如果出现上述错误, 只需要再设置 /mnt/cgroup/A/cpuset.mems 即可. (参考: http://serverfault.com/questions/579555/cgroup-no-space-left-on-device)

    复制代码
    # 同时设置 A 的 cpuset.cpus 和 cpuset.mems
    echo 0 > A/cpuset.cpus
    echo 0 > A/cpuset.mems
    # B组也同样设置
    echo 0 > B/cpuset.cpus
    echo 0 > B/cpuset.mems
    
    # 将当前 shell 加入到 A组
    echo $$ > /mnt/cgroup/A/tasks   <-- 设置过 cpuset.mems 后, 就没有出错了
    stress -c 2
    
    # 再打开一个Shell窗口, 并加入到 B组
    echo $$ > /mnt/cgroup/B/tasks
    stress -c 2
    
    # 再打开第3个 shell 窗口, 用top命令查看CPU使用情况
    top
    top - 15:13:29 up  1:46,  3 users,  load average: 1.01, 0.24, 0.12
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %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
    KiB Mem:   1887872 total,   117216 used,  1770656 free,    11144 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
    
     PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      
    3830 root      20   0  6524   92    0 R  25.0  0.0   0:04.96 stress                                                                                                                       
    3831 root      20   0  6524   92    0 R  25.0  0.0   0:04.97 stress                                                                                                                       
    3834 root      20   0  6524   92    0 R  25.0  0.0   0:03.56 stress                                                                                                                       
    3833 root      20   0  6524   92    0 R  24.6  0.0   0:03.56 stress
    复制代码

    从上面的结果可以看出, 虽然 stress 命令指定了 -c 2(意思是在2个CPU上运行), 但是由于A和B都只绑定了CPU0,

    所以虽然是双核的机器, 它们所占用的CPU总量却只有 100%, 而不是实例1 中的 200%.

    如果将B组的物理CPU绑定到CPU1, 那么应该所有 stress 的进程都占用 50%, CPU资源的总量变为 200%.

    下面将B组的物理CPU绑定为CPU1, 看看结果是否和我们的预期一样.

    复制代码
    # 在 B组的 shell 窗口中执行以下命令
    echo 1 > /mnt/cgroup/B/cpuset.cpus
    cat /mnt/cgroup/B/cpuset.cpus
    1
    stress -c 2
    
    # 在 A组的 shell 窗口中执行以下命令
    stress -c 2
    
    # 在第3个shell窗口中用top命令查看执行结果
    top
    top - 15:20:07 up  1:53,  3 users,  load average: 0.38, 0.83, 0.56
    Tasks:  78 total,   5 running,  73 sleeping,   0 stopped,   0 zombie
    %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
    KiB Mem:   1887872 total,   117340 used,  1770532 free,    11168 buffers
    KiB Swap:  3982332 total,        0 used,  3982332 free,    47088 cached
    
      PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND                                                                                                                      
     3854 root      20   0  6524   88    0 R  49.9  0.0   0:03.76 stress                                                                                                                       
     3857 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
     3858 root      20   0  6524   92    0 R  49.9  0.0   0:02.29 stress                                                                                                                       
     3855 root      20   0  6524   88    0 R  49.6  0.0   0:03.76 stress
    复制代码

    果然, 和预期一致. A组中的 stress 和 B组中的 stress 在各自的物理CPU上都占用了 100% 左右的CPU使用率.

    实例4 - cgroup 对使用的内存的控制

    cgroup 对内存的控制也很简单, 只要挂载cgroup时, 指定 -o memory

    # 首先之前挂载的 cpuset 子系统
    umount /mnt/cgroup
    
    # 挂载cgroup 文件系统, 指定 -o memeory
    mount -o memory -t cgroup memcg /mnt/cgroup/
    mount: special device memcg does not exist

    出现以上错误的原因可能是因为debian系统中, 默认没有启动 cgroup 的memory子系统. 可以通过以下方法确认:

    复制代码
    cat /proc/cgroups 
    #subsys_name    hierarchy    num_cgroups    enabled
    cpuset    0    1    1
    cpu    0    1    1
    cpuacct    0    1    1
    memory    1    1    0              <-- 这里的 enabled 是 0
    devices    0    1    1
    freezer    0    1    1
    net_cls    0    1    1
    blkio    0    1    1
    perf_event    0    1    1
    复制代码

    为了默认启用memory子系统, 可以设置 grub选项

    vim /etc/default/grub
    # 修改 GRUB_CMDLINE_LINUX=""  ==> GRUB_CMDLINE_LINUX="cgroup_enable=memory"
    # 保存后, 更新grub.cfg
    update-grub
    reboot

    重启之后, 发现 /proc/cgroups 中的memory已经 enabled, 并且也可以挂载 memcg了

    复制代码
    cat /proc/cgroups 
    #subsys_name    hierarchy    num_cgroups    enabled
    cpuset    0    1    1
    cpu    0    1    1
    cpuacct    0    1    1
    memory    1    1    1
    devices    0    1    1
    freezer    0    1    1
    net_cls    0    1    1
    blkio    0    1    1
    perf_event    0    1    1
    
    # 挂载cgroup 的memory子系统
    mount -t cgroup -o memory memcg /mnt/cgroup
    ls -l /mnt/cgroup/   <-- 可以看到有很多 memory 相关的配置
    total 0
    -rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.clone_children
    --w--w--w- 1 root root 0 Aug 28 15:54 cgroup.event_control
    -rw-r--r-- 1 root root 0 Aug 28 15:54 cgroup.procs
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.failcnt
    --w------- 1 root root 0 Aug 28 15:54 memory.force_empty
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.limit_in_bytes   <-- 限制内存使用的配置文件
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.max_usage_in_bytes
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.move_charge_at_immigrate
    -r--r--r-- 1 root root 0 Aug 28 15:54 memory.numa_stat
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.oom_control
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.soft_limit_in_bytes
    -r--r--r-- 1 root root 0 Aug 28 15:54 memory.stat
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.swappiness
    -r--r--r-- 1 root root 0 Aug 28 15:54 memory.usage_in_bytes
    -rw-r--r-- 1 root root 0 Aug 28 15:54 memory.use_hierarchy
    -rw-r--r-- 1 root root 0 Aug 28 15:54 notify_on_release
    -rw-r--r-- 1 root root 0 Aug 28 15:54 release_agent
    -rw-r--r-- 1 root root 0 Aug 28 15:54 tasks
    复制代码

    开始实验:

    1. 重启系统 (为了保证内存的干净)
    2. 挂载 memcg
    3. 在挂载的 /mnt/cgroup 中创建 组A
    4. 将当前shell 加入到 组A
    5. 不限制组A的内存, 压缩内核源码包, 并观察压缩前后内存的变化
    6. 重复步骤 1 ~ 4
    7. 限制组A的内存为 10MB, 再次压缩内核源码包, 并观察压缩前后内存的变化
    复制代码
    # 重启系统
    reboot
    
    # 挂载 memcg
    mount -t cgroup -o memory memcg /mnt/cgroup
    
    # 创建 组A
    mkdir /mnt/cgroup/A
    
    # 将当前 shell 加入到组A
    echo $$ > /mnt/cgroup/A/tasks
    
    # 测试不限制内存时, 内存的使用情况, 这里不用linux源码也可以, 但最好用个大点的文件夹来压缩, 以便更容易看出内存的变化.
    free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
                 total       used       free     shared    buffers     cached
    Mem:          1843        122       1721          0          9         43
    -/+ buffers/cache:         68       1774
    Swap:         3888          0       3888
                 total       used       free     shared    buffers     cached
    Mem:          1843       1744         99          0         26       1614
    -/+ buffers/cache:        104       1739
    Swap:         3888          0       3888
    
    # 重启系统
    reboot
    
    # 挂载 memcg
    mount -t cgroup -o memory memcg /mnt/cgroup
    
    # 创建 组A
    mkdir /mnt/cgroup/A
    
    # 将当前 shell 加入到组A
    echo $$ > /mnt/cgroup/A/tasks
    
    # 限制 组A 的内存使用量最大为 10MB
    echo 10M > /mnt/cgroup/A/memory.limit_in_bytes
    
    # 测试限制内存为 10MB 时, 内存的使用情况.
    rm -rf linux-source-3.2.tar.gz
    free -m; tar czvf linux-source-3.2.tar.gz /path/to/linux-source-3.2/ > /dev/null; free -m;
                 total       used       free     shared    buffers     cached
    Mem:          1843        122       1721          0         10         43
    -/+ buffers/cache:         68       1774
    Swap:         3888          0       3888
                 total       used       free     shared    buffers     cached
    Mem:          1843        194       1649          0         14         48
    -/+ buffers/cache:        131       1712
    Swap:         3888          0       3888
    复制代码

    从上面的结果可以看出限制内存是起了作用的.

    不限制内存时, tar 压缩前后 buffer + cache 内存从 (9MB + 43MB) ==> (26MB + 1614MB)  增大了 1588MB

    限制内存后, tar 压缩前后 buffer + cache 内存从 (10MB + 43MB) ==> (14MB + 48MB)  增大了 9MB

    总结

    简单的实验就发现 cgroup 如此强大的控制能力(而且配置也很简单), 这也就难怪LXC等容器技术能如此强大, 如此流行.

    cgroup 的配置文件很多, 上面的实例中只简单使用了其中的几个配置文件, 如果想深入了解 cgroup, 更好的利用cgroup的话,

    还得找个介绍cgroup配置文件的文档来研究一下, 这篇博客提供的内容还远远不够.

  • 相关阅读:
    String 类的常用方法都有那些?
    == 和 equals 的区别是什么
    java【Scanner,Random,ArrayList】的用法(了解80%~90%)
    java无参与有参以及setter和getter方法(练习题)【就事论事】
    java无参与有参以及setter和getter方法(了解)
    不能只学习,还得有玩
    java封装方法(了解)
    java数组,冒泡排序,选择排序(了解80%~90%)
    关于LDEA软件设置背景(详细)
    java运算符,判断符(了解)
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5280932.html
Copyright © 2020-2023  润新知