zoukankan      html  css  js  c++  java
  • Linux Cgroups

    Linux Cgroups

    Namespace是用來實現進程之間的隔離,但是并没有限制其空间的大小。如果想要限制一个进程可以使用的空间,保证各个进程之间不会互相争抢就要用到
    Cgroups。

    Linux Cgroups(Linux Control Groups)提供了对一组进程及将来子进程的资源限制、控制、统计的能力。这些资源包括cpu、内存、存储、网络
    。通过Cgroups,可以方便的控制某个进程占用的资源,并可以实施监控和统计信息。

    Cgroups中的三个组件

    • cgroup 是对进程分组管理的一种机制,一个cgroup包含一组进程,并可以在这个cgroup上增加Linux subsystem的各种参数配置,将一组进程和一
      组subsystem的系统参数关联起来。

    • subsystem 是一组资源控制的模块。包含以下几项。

      • blkio 设置对块设备输入输出的访问控制。例如磁盘
      • cpu 设置cgroup中进程的cpu被调度策略。
      • cpuacct 可以统计cgroup中进程的cpu占用。
      • cpuset 在多核机器上,设置cgroup中进程可以使用的cpu和内存。此处仅限于NUMA架构。
      • devices 控制cgroup对设备的访问。
      • freezer 挂起(suspend)和恢复(resue) cgroup中的进程。
      • memory 用于控制cgroup中进程的内存占用。
      • net_cls 将cgroup中进程产生的网络包分类,便于linux tc(traffic controller)可以根据分类区分出来自某个cgroup包并做监控。
      • net_prio 设置cgroup中进程产生的网络流量的优先级。
      • ns 使cgroup中的进程在新的Namespace中fork新进程时,创建一个新的cgroup,这个cgroup包含新的Namespace中的进程。

    每个subsystem会关联到定义的cgroup,并对这个cgroup中的进程做限制和控制。这些subsystem是逐步合并到内核中的,可以安装apt-get install
    cgroup-bin 然后通过 lssubsys -a 查看

    • hierarchy 把一组cgroup串成一个柱状结构,这样的树便是一个hierarchy,通过这种结构,Cgroups可以做到继承。

    三个组件的关系

    • 系统创建hierarchy 之后,所有的进程都会加入这个hierarchy的cgroup的根节点。在这个cgroup根节点是hierarchy默认创建的。
    • 一个subsystem只能附加到一个hierarchy上面。
    • 一个进程可以作为多个cgroup的成员,但是cgroup必须在不同的hierarchy中。
    • 一个进程fork的子进程和父进程在同一个cgroup中也可以根据需要移到其他cgroup中。

    Kernel接口

    前面说道Cgroups中的hierarchy是一种树状结构,Kernel为了对Cgroups的配置更直观,也会显示为树状结构。下面进行实例,了解如何操作Cgroups。

    1. 首先创建并挂在一个hierarchy(cgroup树),如下.

      leon@leon:~$ mkdir cgroup-test
      leon@leon:~$ sudo mount -t cgroup -o none,name=cgroup1 cgroup1 ./cgroup-test/
      leon@leon:~$ ls ./cgroup-test/
      cgroup.clone_children  cgroup.procs  cgroup.sane_behavior  notify_on_release  release_agent  tasks
      

      这些文件就是这个hierarchy中cgroup根节点的配置项,上面这些文件含义如下。

      • cgroup.clone_children, cpuset的subsystem会读取这个文件的配置,如果值是1(默认值0),子cgroup才会继承父cgroup的cpuset配置。
      • cgroup.procs 是树中当前结点cgroup的进程组id,现在的位置是在根节点,这个文件中会有现在系统中所有进程组的ID。
      • notify_on_release和release_agent会在一起使用。notify_on_release标识当这个cgroup最后一个进程退出的时候是否执行了
        release_agent;release_agent则是一个路径,通常用作进程退出后自动清理掉不再使用的cgroup。
      • tasks标识该cgroup下面的进程ID,如果把一个进程ID写到tasks中便会将相应的进程加入到这个cgroup中。
    2. 然后创建刚才建立的hierarchy上cgroup根节点中扩展出的两个子cgroup。

    可以看到创建子文件夹的同时,Kernel会标记这个cgroup的子cgroup,他们会继承父cgroup的属性。
    
    1. 在cgroup中添加和移动进程
      一个进程在Cgroups的hierarchy中,只能在一个cgroup节点上存在,系统所有进程都会默认在根节点上存在,可以将进程移动到其他节点上,只需要将
      进程ID移动到cgroup节点的tasks文件即可。

    可以看到当前进程已经被添加到cgroup-1中了。**第一行**
    
    1. 通过subsystem限制cgroup进程的资源
      上面的hierarchy没有关系任何的subsystem,所以没有限制cgroup占用的系统资源。本质系统默认为subsystem创建了hierarchy,比如memory的hierarchy。

      可以看到/sys/fs/cgroup/memory目录挂载在memory subsystem的hierarchy上。下面进入到memory目录下创建cgroup。限制内存。

    这样就创建成功,并添加了内存使用的限制。
    

     可以看到9752 使用内存最大为100M
    

    Docker是如何使用Cgroups的

    Docker是通过Cgroups实现容器资源的限制和监控。

    可以看到最大限制是134217728 使用的是1970176.这些都是我们在/sys/fs/cgroup/memory中找到的。由此可见docker本质上也是这样做的。
    

    Go语言实现Cgroups限制容器资源

    在Namespace的基础之上增加Cgroup的限制,使其具有限制内存的功能。

    package main
    
    import (
    	"os"
    	"os/exec"
    	"log"
    	"syscall"
    	"path"
    	"fmt"
    	"io/ioutil"
    	"strconv"
    )
    
    const cgroupMemoryHierarchyMount = "/sys/fs/cgroup/memory" //内存挂载点的路径
    func main() {//
        if os.Args[0] == "/proc/self/exe"{
        	fmt.Printf("current pid %d", syscall.Getpid())
        	fmt.Println()
        	cmd := exec.Command("sh", "-c" ,"strees --vm-bytes 200m --vm-keep -m 1")  // 之前我们通过命令行,这里命令还是一样的。
        	cmd.SysProcAttr = &syscall.SysProcAttr{
        	}
        	cmd.Stdin = os.Stdin
        	cmd.Stdout = os.Stdout
        	cmd.Stderr = os.Stderr
        	if err := cmd.Run();err!=nil{
        		fmt.Println(err)
        	    os.Exit(1)
        	}
        }
        cmd :=exec.Command("/proc/self/exe")
        cmd.SysProcAttr = &syscall.SysProcAttr{
        	Cloneflags:syscall.CLONE_NEWUTS|syscall.CLONE_NEWPID|syscall.CLONE_NEWNS,
        }
        cmd.Stdin = os.Stdin
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        if err := cmd.Start(); err !=nil{
        	fmt.Println("error", err)
        	os.Exit(1)
        }else {
        	//获取fork的进程pid
        	fmt.Printf("%v" ,cmd.Process.Pid)
        	// 在系统中默认创建挂在了memory subsystem的hierarchy上创建Cgroup
        	os.Mkdir(path.Join(cgroupMemoryHierarchyMount,"testmemorylimit"),0755)
        	
        	// 将容器加入到这个Cgroup中
        	ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount,"testmemorylimit","tasks"),[]byte(strconv.Itoa(cmd.Process.Pid)),0644)
        	
        	//限制cgroup的使用
        	ioutil.WriteFile(path.Join(cgroupMemoryHierarchyMount,"testmemorylimit","memory.limit_in_bytes"),[]byte("100m"),0644)
        	}
        	cmd.Process.Wait()
        
        }
    
    

    通过top就可以查看。

  • 相关阅读:
    移动端疑难特性、兼容性
    微信浏览器video播放视频踩坑
    【canvas学习笔记八】像素操作
    【canvas学习笔记七】混合和裁剪
    【canvas学习笔记六】状态保存和变换
    【canvas学习笔记五】使用图片
    【canvas学习笔记四】绘制文字
    【canvas学习笔记三】样式和颜色
    【canvas学习笔记二】绘制图形
    【canvas学习笔记一】基本认识
  • 原文地址:https://www.cnblogs.com/Leon-The-Professional/p/9954120.html
Copyright © 2011-2022 走看看