不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

使用过Docker的人都知道,Docker使用cgroup来控制进程的资源使用量,在OpenStack中使用KVM同样也存在这个问题,KVM虽然可以做内核的隔离,但是使用起主机上的CPU来,也是互相争抢的,需要使用cgroup控制资源使用量。

Control Group又称cgroup,用于控制进程的资源使用:CPU, Disk I/O, Memory, Network等。

Cgroup有几个重要的概念:

  • 任务:对应于进程,将进程ID放到cgroup里面,就算cgroup的一个任务,受cgroup控制

  • 层次:

    • cgroup是分层次的,子cgroup会继承父cgroup的设置

    • Cgroup的管理通常使用file system的接口,一个cgroup会被mount成一个cgroup的文件系统,则层次结构对应于文件夹结构

  • 子系统:系统的资源被不同的子系统控制

    • blkio -- 为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB等等)。

    • cpu -- 使用调度程序提供对CPU的cgroup任务访问。

    • cpuacct -- 自动生成cgroup中任务所使用的CPU报告。

    • cpuset -- 为cgroup中的任务分配独立CPU (在多核系统)和内存节点。

    • devices -- 可允许或者拒绝cgroup中的任务访问设备。

    • freezer -- 挂起或者恢复cgroup中的任务。

    • memory -- 设定cgroup中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。

    • net_cls -- 使用等级识别符(classid)标记网络数据包,可允许Linux流量控制程序tc识别从 具体cgroup中生成的数据包。

    • ns -- 名称空间子系统。

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

一、对CPU的控制

CFS (Completely Fair Scheduler) :

  • 将所有可运行的任务放入一棵红黑树,key是vruntime

  • 红黑树是平衡的,左面的任务得到的时间少,右面的任务得到的时间多,最左面的任务有最高的优先级

  • cfs_period_us的意思是cgroup对CPU的调度的干预周期,cfs_quota_us是指则一个周期内这个进程得到的时间片长度。比如cfs_period_us=100000说明100毫秒cgroup进行一次干预,cfs_quota_us=25000表示在100毫秒里面,这个进程能够得到25毫秒的时间片,如果对cgroup进行的修改,则要等到下个100毫秒才起作用

  • cpu.shares是一个相对值,进程之间的cpu使用率按照这个数字的比例来

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

查看cpuset,在如下路径下面:

cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,relatime,cpuset)

cat ubuntutest.libvirt-qemu/cpuset.cpus #0-3

cat ubuntutest2.libvirt-qemu/cpuset.cpus #0-3

两个VM都同时使用四个CPU,为了查看CPU调度,我们使用一个CPU

关闭VM,设置cpuset.cpus

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

重启VM

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

在两台虚拟机上创建一个无限循环的python程序

没有设置cgroup的时候,两台虚拟机同时运行这个程序

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

设置cpu.shares

查看现在的设置

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

修改ubuntutest2的设置

echo 4096 > ubuntutest2.libvirt-qemu/cpu.shares

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

也可以通过virsh设置和查看

virsh schedinfo ubuntutest --set cpu_shares=2048

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

设置vcpu_quota

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

二、对block I/O的控制

查看major number和minor number

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

相对值:范围在100到1000

echo 8:0 500 > blkio.weight_device

绝对值(bytes per second):

echo "8:0 10485760" > /cgroup/blkio/testcg/blkio.throttle.read_bps_device

echo "8:0 10485760" > /cgroup/blkio/testcg/blkio.throttle.write_bps_device

使用virsh

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

使用iotop -P -o查看速度

设置cache='none'

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

设置写入速度

echo "8:0 10485760" > ubuntutest.libvirt-qemu/blkio.throttle.write_bps_device

echo "8:0 20971520" > ubuntutest.libvirt-qemu/blkio.throttle.write_bps_device

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

四、对网络I/O的控制

对于virsh命令,当前net_cls还不支持

可以通过TC直接控制网卡的流量

TC有两种类型控制网络I/O.

第一种类型为:Classless Queuing Disciplines,也即不分类

默认为pfifo_fast

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

pfifo是基于ToS和priomap分到不同的队列中

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

网络包里面有TOS,总共四位

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

代表5种类型

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

这是priomap,设置了不同的ToS去哪个队列

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

还有一种队列名叫SFQ, Stochastic Fair Queuing随机公平队列

会有很多的FIFO的队列,TCP Session或者UDP stream会被分配到域名购买某个队列。

包会RoundRobin的从各个队列中取出发送。

这样不会一个Session占据所有的流量。

但不是每一个Session都有一个队列,而是有一个Hash算法,将大量的Session分配到有限的队列中。

这样两个Session会共享一个队列,也有可能互相影响。

Hash函数会经常改变,从而session不会总是相互影响。

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

还有一种队列名叫TBF, Token Bucket Filter

它有两个概念Tokens and buckets

所有的包排成队列进行发送,但不是到了队头就能发送,而是需要拿到Token才能发送

Token根据设定的速度rate生成,所以即便队列很长,也是按照rate进行发送的

当没有包在队列中的时候,Token还是以既定的速度生成,但是不是无限累积的,而是放满了buckets为止,篮子的大小常用burst/buffer/maxburst来设定

Buckets会避免下面的情况:当长时间没有包发送的时候,积累了大量的Token,突然来了大量的包,每个都能得到Token,造成瞬间流量大增

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

第二种类型:Classful Queuing Disciplines,是分类的

常见的为HTB, Hierarchical Token Bucket,有以下的概念

  • Shaping:仅仅发生在叶子节点,依赖于其他的Queue

  • Borrowing: 当网络资源空闲的时候,借点过来为我所用

  • Rate:设定的发送速度

  • Ceil:最大的速度,和rate之间的差是最多能向别人借多少

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

type  of class

class  state

HTB  internal state

action  taken

leaf

< rate

HTB_CAN_SEND

Leaf  class will dequeue queued bytes up to available tokens (no more than burst  packets)

leaf

> rate,  < ceil

HTB_MAY_BORROW

Leaf  class will attempt to borrow tokens/ctokens from parent class. If tokens are  available, they will be lent in quantum increments and the leaf  class will dequeue up to cburst bytes

leaf

> ceil

HTB_CANT_SEND

No  packets will be dequeued. This will cause packet delay and will increase  latency to meet the desired rate.

inner,  root

< rate

HTB_CAN_SEND

Inner  class will lend tokens to children.

inner,  root

> rate,  < ceil

HTB_MAY_BORROW

Inner  class will attempt to borrow tokens/ctokens from parent class, lending them to  competing children in quantum increments per request.

inner,  root

> ceil

HTB_CANT_SEND

Inner  class will not attempt to borrow from its parent and will not lend tokens/ctokens  to children classes.

例如创建一个如下的htb树

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

创建一个HTB的qdisc在eth0上,句柄为1:,default 12表示默认发送给1:12

tc qdisc add dev eth0 root handle 1: htb default 12

创建一个root class,然后创建几个子class

同一个root class下的子类可以相互借流量,如果直接不在qdisc下面创建一个root class,而是直接创建三个class,他们之间是不能相互借流量的。

tc class add dev eth0 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps

tc class add dev eth0 parent 1:1 classid 1:10 htb rate 30kbps ceil 100kbps

tc class add dev eth0 parent 1:1 classid 1:11 htb rate 10kbps ceil 100kbps

tc class add dev eth0 parent 1:1 classid 1:12 htb rate 60kbps ceil 100kbps

创建叶子qdisc,分别为fifo和sfq

tc qdisc add dev eth0 parent 1:10 handle 20: pfifo limit 5

tc qdisc add dev eth0 parent 1:11 handle 30: pfifo limit 5

tc qdisc add dev eth0 parent 1:12 handle 40: sfq perturb 10

设定规则:从1.2.3.4来的,发送给port 80的包,从1:10走;其他从1.2.3.4发送来的包从1:11走;其他的走默认

tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 match ip dport 80 0xffff flowid 1:10

tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 flowid 1:11

当同时发大量的包的时候会出现下面的图形

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

时间0的时候,0,1,2都以90k的速度发送数据,在时间3的时候,将0的发送停止,红色的线归零,剩余的流量按照比例分给了蓝色的和绿色的线。

在时间6的时候,将0的发送重启为90k,则蓝色和绿色的流量返还给红色的流量。

在时间9的时候,将1的发送停止,绿色的流量为零,剩余的流量按照比例分给了蓝色和红色。

在时间12,将1的发送恢复,红色和蓝色返还流量。

在时间15,将2的发送停止,蓝色流量为零,剩余的流量按照比例分给红色和绿色。

在时间19,将1的发送停止,绿色的流量为零,所有的流量都归了红色。

对于如下的图谱图,创建如下的规则

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

tc qdisc add dev tap3 root handle 1: htb

tc class add dev tap3 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps

tc class add dev tap3 parent 1:1 classid 1:10 htb rate 20kbps ceil 100kbps

tc class add dev tap3 parent 1:1 classid 1:11 htb rate 80kbps ceil 100kbps

tc qdisc add dev tap3 parent 1:10 handle 20: pfifo limit 5

tc qdisc add dev tap3 parent 1:11 handle 30: pfifo limit 5

tc filter add dev tap3 protocol ip parent 1:0 prio 1 u32 match ip src 192.168.57.100 flowid 1:10

tc filter add dev tap3 protocol ip parent 1:0 prio 1 u32 match ip src 192.168.57.101 flowid 1:11

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

五、Libvirt可以通过hooks来设置cgroup

Libvirt提供hook功能,可以再下面的事件发生的时候,调用脚本做一些事情

  • 事件一:The libvirt daemon starts, stops, or reloads its configuration

  • 事件二:A QEMU guest is started or stopped

  • 事件三:A network is started or stopped or an interface is plugged/unplugged to/from the network

Hook在目录/etc/libvirt/hooks下:

  • /etc/libvirt/hooks/daemon在事件一发生的时候被调用

  • /etc/libvirt/hooks/qemu对应事件二

  • /etc/libvirt/hooks/network对应事件三

脚本可以是bash也可以是python

  • #!/bin/bash

  • #!/usr/bin/python

脚本参数

  • Object:例如guest的名称

  • Operation:例如start

  • sub-operation

  • extra argument

  • 另外domain的xml作为stdin

注意:不可以在hook脚本中调用virsh的api,容易引起死锁

简单的hook脚本,打印参数和stdin

  • /etc/libvirt/hooks/daemon

  • /etc/libvirt/hooks/qemu

  • /etc/libvirt/hooks/network

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

要加载hook脚本,必须stop然后start libvirt-bin

  • service libvirt-bin stop

  • service libvirt-bin start

  • 不可以restart

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

测试脚本

tail -f /tmp/hook.log

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

关闭这个实例

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

会看到新的日志

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

复杂的hook脚本

  • 禁止ICMP

  • 设置CPU Share

  • 设置网络带宽

修改/etc/libvirt/hooks/qemu

  • 处理started和stopped事件

  • 在started事件发生后,也即虚拟机创建后

    • 创建一个文件夹,将domain的xml放在文件夹里面

    • 然后调用python脚本

      • /etc/libvirt/hooks/qemu.d/disable_icmp.py

      • /etc/libvirt/hooks/qemu.d/update_cpu_share.py

      • /etc/libvirt/hooks/qemu.d/add_tc.py

  • 在stopped事件发生后,也即虚拟机关闭后

    • 调用脚本/etc/libvirt/hooks/qemu.d/enable_icmp.py

    • 删除domain文件夹

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

/etc/libvirt/hooks/qemu.d/disable_icmp.py

  • 解析domain的xml文件,得到domain的名称和网卡名称

  • 调用iptables命令

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

/etc/libvirt/hooks/qemu.d/enable_icmp.py

  • 解析domain的xml文件,得到domain的名称和网卡名称

  • 调用iptables命令

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

/etc/libvirt/hooks/qemu.d/update_cpu_share.py

  • 解析domain的xml文件,得到domain的名称和网卡名称

  • 将2048写入cpu.shares文件,默认为1024

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

/etc/libvirt/hooks/qemu.d/add_tc.py

  • 解析domain的xml文件,得到domain的名称和网卡名称

  • 调用tc添加qdisc到虚拟网卡

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

我们最后测试一下

启动虚拟机virsh start ubuntutest4

在tail -f /tmp/hook.log中

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

运行iptables –nvL

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

查看/sys/fs/cgroup/cpu/machine/ubuntutest4.libvirt-qemu/cpu.shares

查看tc qdisc show dev vnet0

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

文件夹也创建了

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

删除虚拟机virsh destroy ubuntutest4

在tail -f /tmp/hook.log中

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

运行iptables –nvL

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

文件夹也删除了

不仅Docker会使用Control Group,KVM也会使用Cgroup来控制资源分配

上一篇:判断是否处于容器内


下一篇:SQL-labs在docker里创建失败2021-10-03