Create Cgroup - Linux的IO资源隔离.md

This commit is contained in:
wenchao1024
2022-01-20 20:26:50 +08:00
committed by GitHub
parent 0c5f0b64e2
commit 981744aff4

View File

@@ -0,0 +1,399 @@
# Cgroup - Linux的IO资源隔离
## Linux的IO隔离
跟内存管理那部分复杂度类似IO的资源隔离要讲清楚也是比较麻烦的。这部分内容都是这样配置起来简单但是要理解清楚确没那么简单。这次是跟Linux内核的IO实现有关系。对于IO的速度限制实现思路跟CPU和内存都不一样。CPU是针对进程占用时间的比例限制内存是空间限制而当我们讨论IO资源隔离的时候实际上有两个资源需要考虑一个是空间另一个是速度。对于空间来说这个很简单大不了分区就是了。现实手段中分区、LVM、磁盘配额、目录配额等等不同的分区管理方式不同的文件系统都给出了很多不同的解决方案。所以空间的限制实际上不是cgroup要解决的问题那就是说我们在这里要解决的问题是如何进行IO数据传输的速度限制。
限速这件事情现实中有很多模型、算法去解决这个问题。比如如果我们想控制高速公路上的汽车单位时间通过率就让收费站每隔固定时间周期只允许通过固定个数的车就好了。这是一种非常有效的控制手段漏斗算法。现实中这种算法可能在特定情况下会造成资源浪费以及用户的体验不好于是又演化出令牌桶算法。这里我们不去详细分析这些算法但是我们要知道对io的限速基本是一个漏斗算法的限速效果。无论如何这种限速都要有个“收费站”这样的设施来执行限速那么对于Linux的IO体系来说这个”收费站”建在哪里呢于是我们就必须先来了解一下
### Linux的IO体系
Linux的IO体系是个层级还算清晰的结构它基本上分成了如图示这样几层
**Linux的IO体系层次结构**
我们可以通过追踪一个read()系统调用来一窥这些层次的结构当read()系统调用发生内核首先会通过汇编指令引发一个软中断然后根据中断传入的参数查询系统调用影射表找到read()对应的内核调用方法名并去执行相关调用这个系统调用名一般情况下就是sys_read()。从此,便开始了调用在内核中处理的过程的第一步:
1. VFS层虚拟文件系统层。由于内核要跟多种文件系统打交道而每一种文件系统所实现的数据结构和相关方法都可能不尽相同所以内核抽象了这一层专门用来适配各种文件系统并对外提供统一操作接口。
2. 文件系统层:不同的文件系统实现自己的操作过程,提供自己特有的特征,具体不多说了,大家愿意的话自己去看代码即可。
3. 页缓存层我们的老朋友了如果不了解缓存是什么的可以先来看看Linux内存资源管理部分。
4. 通用块层由于绝大多数情况的io操作是跟块设备打交道所以Linux在此提供了一个类似vfs层的块设备操作抽象层。下层对接各种不同属性的块设备对上提供统一的Block IO请求标准。
5. IO调度层因为绝大多数的块设备都是类似磁盘这样的设备所以有必要根据这类设备的特点以及应用的不同特点来设置一些不同的调度算法和队列。以便在不同的应用环境下有针对性的提高磁盘的读写效率这里就是大名鼎鼎的Linux电梯所起作用的地方。针对机械硬盘的各种调度方法就是在这实现的。
6. 块设备驱动层驱动层对外提供相对比较高级的设备操作接口往往是C语言的而下层对接设备本身的操作方法和规范。
7. 块设备层:这层就是具体的物理设备了,定义了各种真对设备操作方法和规范。
根据这几层的特点如果你是设计者你会在哪里实现真对块设备的限速策略呢6、7都是相关具体设备的如果在这个层次提供那就不是内核全局的功能而是某些设备自己的feture。文件系统层也可以实现但是如果要全局实现也是不可能的需要每种文件系统中都实现一遍成本太高。所以可以实现限速的地方比较合适的是VFS、缓存层、通用块层和IO调度层。而VFS和page cache这样的机制并不是面向块设备设计的都是做其他事情用的虽然也在io体系中但是并不适合用来做block io的限速。所以这几层中最适合并且成本最低就可以实现的地方就是IO调度层和通用块层。IO调度层本身已经有队列了我们只要在队列里面实现一个限速机制即可但是在IO调度层实现的限速会因为不同调度算法的侧重点不一样而有很多局限性从通用块层实现的限速原则上就可以对几乎所有的块设备进行带宽和iops的限制。截止目前4.3.3内核IO限速主要实现在这两层中。
根据IO调度层和通用块层的特点这两层分别实现了两种不同策略的IO控制策略也是目前blkio子系统提供的两种控制策略一个是权重比例方式的控制另一个是针对IO带宽和IOPS的控制。
### IO调度层
我们需要先来认识一下IO调度层。这一层要解决的核心问题是如何提高块设备IO的整体性能这一层也主要是针对用途最广泛的机械硬盘结构而设计的。众所周知机械硬盘的存储介质是磁介质并且是盘状用磁头在盘片上移动进行数据的寻址这类似播放一张唱片。这种结构的特点是顺序的数据读写效率比较理想但是如果一旦对盘片有随机读写那么大量的时间都会浪费在磁头的移动上这时候就会导致每次IO的响应时间很长极大的降低IO的响应速度。磁头在盘片上寻道的操作类似电梯调度如果在寻道的过程中能把路过的相关磁道的数据请求都“顺便”处理掉那么就可以在比较小影响响应速度的前提下提高整体IO的吞吐量。所以一个好的IO调度算法的需求就此产生。在最开始的阶段Linux就把这个算法命名为Linux电梯算法。目前在内核中默认开启了三种算法其实严格算应该是两种因为第一种叫做noop就是空操作调度算法也就是没有任何调度操作并不对io请求进行排序仅仅做适当的io合并的一个fifo队列。
目前内核中默认的调度算法应该是cfq叫做完全公平队列调度。这个调度算法人如其名它试图给所有进程提供一个完全公平的IO操作环境。它为每个进程创建一个同步IO调度队列并默认以时间片和请求数限定的方式分配IO资源以此保证每个进程的IO资源占用是公平的cfq还实现了针对进程级别的优先级调度这里我们不去细节解释。我们在此只需要知道既然时间片分好了优先级实现了那么cfq肯定是实现进程级别的权重比例分配的最好方案。内核就是这么做的cgroup blkio的权重比例限制就是基于cfq调度器实现的。如果你要使用权重比例分配请先确定对应的块设备的IO调度算法是cfq。
查看和修改的方法是:
```
[zorro@zorrozou-pc0 ~]$ cat /sys/block/sda/queue/scheduler
noop deadline [cfq]
[zorro@zorrozou-pc0 ~]$ echo cfq > /sys/block/sda/queue/scheduler
```
cfq是通用服务器比较好的IO调度算法选择对桌面用户也是比较好的选择。但是对于很多IO压力较大的场景就并不是很适应尤其是IO压力集中在某些进程上的场景。因为这种场景我们需要更多的满足某个或者某几个进程的IO响应速度而不是让所有的进程公平的使用IO比如数据库应用。
deadline调度最终期限调度就是更适应这样的场景的解决方案。deadline实现了四个队列其中两个分别处理正常read和write按扇区号排序进行正常io的合并处理以提高吞吐量.因为IO请求可能会集中在某些磁盘位置这样会导致新来的请求一直被合并于是可能会有其他磁盘位置的io请求被饿死。于是实现了另外两个处理超时read和write的队列按请求创建时间排序如果有超时的请求出现就放进这两个队列调度算法保证超时达到最终期限时间的队列中的请求会优先被处理防止请求被饿死。由于deadline的特点无疑在这里无法区分进程也就不能实现针对进程的io资源控制。
其实不久前内核还是默认标配四种算法还有一种叫做as的算法Anticipatory scheduler预测调度算法。一个高大上的名字搞得我一度认为Linux内核都会算命了。结果发现无非是在基于deadline算法做io调度的之前等一小会时间如果这段时间内有可以合并的io请求到来就可以合并处理提高deadline调度的在顺序读写情况下的数据吞吐量。其实这根本不是啥预测我觉得不如叫撞大运调度算法。估计结果是不仅没有提高吞吐量还降低了响应速度所以内核干脆把它从默认配置里删除了。毕竟Linux的宗旨是实用。
根据以上几种io调度算法的简单分析我们也能对各种调度算法的使用场景有一些大致的思路了。从原理上看cfq是一种比较通用的调度算法是一种以进程为出发点考虑的调度算法保证大家尽量公平。deadline是一种以提高机械硬盘吞吐量为思考出发点的调度算法只有当有io请求达到最终期限的时候才进行调度非常适合业务比较单一并且IO压力比较重的业务比如数据库。而noop呢其实如果我们把我们的思考对象拓展到固态硬盘那么你就会发现无论cfq还是deadline都是针对机械硬盘的结构进行的队列算法调整而这种调整对于固态硬盘来说完全没有意义。对于固态硬盘来说IO调度算法越复杂效率就越低因为额外要处理的逻辑越多。所以固态硬盘这种场景下使用noop是最好的deadline次之而cfq由于复杂度的原因无疑效率最低。但是如果你想对你的固态硬盘做基于权重比例的IO限速的话那就没啥办法了毕竟这时候效率并不是你的需求要不你限速干嘛
### 通用块设备层
这层的作用我这里就不再复述了本节其实主要想解释的是既然这里实现了对blkio的带宽和iops的速度限制那么有没有什么需要注意的地方这自然是有的。首先我们还是要先来搞清楚IO中的几个概念。
**一般IO**
一个正常的文件io需要经过vfs -> buffer\page cache -> 文件系统 -> 通用块设备层 -> IO调度层 -> 块设备驱动 -> 硬件设备这所有几个层次。其实这就是一般IO。当然不同的状态可能会有变化比如一个进程正好open并read一个已经存在于page cache中的数据。这样的事情我们排出在外不分析。那么什么是比较特别的io呢
**Direct IO**
中文也可以叫直接IO操作其特点是VFS之后跳过buffer\page cache层直接从文件系统层进行操作。那么就意味着无论读还是写都不会进行cache。我们基本上可以理解这样的io看起来效率要低很多直接看到的速度就是设备的速度并且缺少了cache层对数据的缓存之后文件系统和数据块的操作效率直接暴露给了应用程序块的大小会直接影响io速度。
**Sync IO** & **write-through**:
中文叫做同步IO操作如果是写操作的话也叫write-through这个操作往往容易跟上面的DIO搞混因为看起来他们速度上差不多但是是有本质区别的。这种方式写的数据要等待存储写入返回才能成功返回所以跟DIO效率差不多但是写的数据仍然是要在cache中写入的这样其他一般IO的程度仍然可以使用cache机制加速IO操作。所以这里的sync的意思就是在执行write操作的时候让cache和存储上的数据一致。那么他跟一般IO其实一样数据是要经过cache层的。
**write-back**:
既然明白了write-thuough那么write-back就好理解了无非就是将目前在cache中还没写回存储的脏数据写回到存储。这个名词一般指的是一个独立的过程这个过程不是随着应用的写而发生这往往是内核自己找个时间来单独操作的。说白了就是应用写文件感觉自己很快写完了其实内核都把数据放倒cache里了然后内核自己找时间再去写回到存储上。实际上write-back只是在一般IO的情况下保证数据一致性的一种机制而已。
有人将IO过程中以是否使用缓冲缓存的区别将IO分成了缓存IOBuffered IO和直接IODirect io。其实就是名词上的不同而已。这里面的buffer的含义跟内存中buffer cache有概念上的不同。实际上这里Buffered IO的含义相当于内存中的buffer cache+page cache就是IO经过缓存的意思。到这我们思考一个问题如果cgroup针对IO的资源限制实现在了通用块设备层那么将会对哪些IO操作有影响呢其实原则上说都有影响因为绝大多数数据都是要经过通用块设备层写入存储的但是对于应用程序来说感受可能不一样。在一般IO的情况下应用程序很可能很快的就写完了数据在数据量小于缓存空间的情况下然后去做其他事情了。这时应用程序感受不到自己被限速了而内核在处理write-back的阶段由于没有相关page cache中的inode是属于那个cgroup的信息记录所以所有的page cache的回写只能放到cgroup的root组中进行限制而不能在其他cgroup中进行限制因为root组的cgroup一般是不做限制的所以就相当于目前的cgroup的blkio对buffered IO是没有限速支持的。这个功能将在使用了unified-hierarchy体系的cgroup v2中的部分文件系统ext系列已经得到得到支持目前这个功能还在开发中据说将在4.5版本的内核中正式发布。
而在Sync IO和Direct IO的情况下由于应用程序写的数据是不经过缓存层的所以能直接感受到速度被限制一定要等到整个数据按限制好的速度写完或者读完才能返回。这就是当前cgroup的blkio限制所能起作用的环境限制。了解了这个之后我们就可以来看
## blkio配置方法
### 权重比例分配
我们这次直接使用命令行的方式对cgroup进行操作。在我们的系统上我们现在想创建两个cgroup组一个叫test1一个叫test2。我们想让这两个组的进程在对/dev/sdb设备号为8:16的这个磁盘进行读写的时候按权重比例进行io资源的分配。具体配置方法如下
首先确认系统上已经mount了相关的cgroup目录
```
[root@zorrozou-pc0 ~]# ls /sys/fs/cgroup/blkio/
blkio.io_merged blkio.io_service_bytes_recursive blkio.io_wait_time blkio.sectors blkio.throttle.read_iops_device blkio.weight tasks
blkio.io_merged_recursive blkio.io_serviced blkio.io_wait_time_recursive blkio.sectors_recursive blkio.throttle.write_bps_device blkio.weight_device
blkio.io_queued blkio.io_serviced_recursive blkio.leaf_weight blkio.throttle.io_service_bytes blkio.throttle.write_iops_device cgroup.clone_children
blkio.io_queued_recursive blkio.io_service_time blkio.leaf_weight_device blkio.throttle.io_serviced blkio.time cgroup.procs
blkio.io_service_bytes blkio.io_service_time_recursive blkio.reset_stats blkio.throttle.read_bps_device blkio.time_recursive notify_on_release
```
然后创建两个针对blkio的cgroup
```
[root@zorrozou-pc0 ~]# mkdir /sys/fs/cgroup/blkio/test1
[root@zorrozou-pc0 ~]# mkdir /sys/fs/cgroup/blkio/test2
```
相关目录下会自动产生相关配置项:
```
[root@zorrozou-pc0 ~]# ls /sys/fs/cgroup/blkio/test{1,2}
/sys/fs/cgroup/blkio/test1:
blkio.io_merged blkio.io_service_bytes_recursive blkio.io_wait_time blkio.sectors blkio.throttle.read_iops_device blkio.weight tasks
blkio.io_merged_recursive blkio.io_serviced blkio.io_wait_time_recursive blkio.sectors_recursive blkio.throttle.write_bps_device blkio.weight_device
blkio.io_queued blkio.io_serviced_recursive blkio.leaf_weight blkio.throttle.io_service_bytes blkio.throttle.write_iops_device cgroup.clone_children
blkio.io_queued_recursive blkio.io_service_time blkio.leaf_weight_device blkio.throttle.io_serviced blkio.time cgroup.procs
blkio.io_service_bytes blkio.io_service_time_recursive blkio.reset_stats blkio.throttle.read_bps_device blkio.time_recursive notify_on_release
/sys/fs/cgroup/blkio/test2:
blkio.io_merged blkio.io_service_bytes_recursive blkio.io_wait_time blkio.sectors blkio.throttle.read_iops_device blkio.weight tasks
blkio.io_merged_recursive blkio.io_serviced blkio.io_wait_time_recursive blkio.sectors_recursive blkio.throttle.write_bps_device blkio.weight_device
blkio.io_queued blkio.io_serviced_recursive blkio.leaf_weight blkio.throttle.io_service_bytes blkio.throttle.write_iops_device cgroup.clone_children
blkio.io_queued_recursive blkio.io_service_time blkio.leaf_weight_device blkio.throttle.io_serviced blkio.time cgroup.procs
blkio.io_service_bytes blkio.io_service_time_recursive blkio.reset_stats blkio.throttle.read_bps_device blkio.time_recursive notify_on_release
```
之后我们就可以进行限制了。针对cgroup进行权重限制的配置有**blkio.weight**是单纯针对cgroup进行权重配置的还有**blkio.weight_device**可以针对设备单独进行限制我们都来试试。首先我们想设置test1和test2使用任何设备的io权重比例都是1:2
```
[root@zorrozou-pc0 zorro]# echo 100 > /sys/fs/cgroup/blkio/test1/blkio.weight
[root@zorrozou-pc0 zorro]# echo 200 > /sys/fs/cgroup/blkio/test2/blkio.weight
```
注意权重设置的取值范围为10-1000。然后我们来写一个测试脚本
```
#!/bin/bash
testfile1=/home/test1
testfile2=/home/test2
if [ -e $testfile1 ]
then
rm -rf $testfile1
fi
if [ -e $testfile2 ]
then
rm -rf $testfile2
fi
sync
echo 3 > /proc/sys/vm/drop_caches
cgexec -g blkio:test1 dd if=/dev/zero of=$testfile1 oflag=direct bs=1M count=1023 &
cgexec -g blkio:test2 dd if=/dev/zero of=$testfile2 oflag=direct bs=1M count=1023 &
```
我们dd的时候使用的是direct标记在这使用sync和不加任何标记的话都达不到效果。因为权重限制是基于cfq实现cfq要标记进程而buffered IO都是内核同步无法标记进程。使用iotop查看限制效果
```
[root@zorrozou-pc0 zorro]# iotop -b -n1|grep direct
1519 be/4 root 0.00 B/s 110.00 M/s 0.00 % 99.99 % dd if=/dev/zero of=/home/test2 oflag=direct bs=1M count=1023
1518 be/4 root 0.00 B/s 55.00 M/s 0.00 % 99.99 % dd if=/dev/zero of=/home/test1 oflag=direct bs=1M count=1023
```
却是达到了1:2比例限速的效果。此时对于磁盘读取的限制效果也一样具体测试用例大家可以自己编写。读取的时候要注意仍然要保证读取的文件不在page cache中方法就是echo 3 > /proc/sys/vm/drop_caches。因为在page cache中的数据已经在内存里了直接修改是直接改内存中的内容只有write-back的时候才会经过cfq。
我们再来试一下针对设备的权重分配,请注意设备号的填写格式:
```
[root@zorrozou-pc0 zorro]# echo "8:16 400" > /sys/fs/cgroup/blkio/test1/blkio.weight_device
[root@zorrozou-pc0 zorro]# echo "8:16 200" > /sys/fs/cgroup/blkio/test2/blkio.weight_device
[root@zorrozou-pc0 zorro]# iotop -b -n1|grep direct
1800 be/4 root 0.00 B/s 102.24 M/s 0.00 % 99.99 % dd if=/dev/zero of=/home/test1 oflag=direct bs=1M count=1023
1801 be/4 root 0.00 B/s 51.12 M/s 0.00 % 99.99 % dd if=/dev/zero of=/home/test2 oflag=direct bs=1M count=1023
```
我们会发现这时权重确实是按照最后一次的设置test1和test2变成了2:1的比例而不是1:2了。这里要说明的就是注意blkio.weight_device的设置会覆盖blkio.weight的设置因为前者的设置精确到了设备Linux在这里的策略是越精确越优先。
### 读写带宽和iops限制
针对读写带宽和iops的限制都是绝对值限制所以我们不用两个cgroup做对比了。我们就设置test1的写带宽速度为1M/s:
```
[root@zorrozou-pc0 zorro]# echo "8:16 1048576" > /sys/fs/cgroup/blkio/test1/blkio.throttle.write_bps_device
[root@zorrozou-pc0 zorro]# sync
[root@zorrozou-pc0 zorro]# echo 3 > /proc/sys/vm/drop_caches
[root@zorrozou-pc0 zorro]# cgexec -g blkio:test1 dd if=/dev/zero of=/home/test oflag=direct count=1024 bs=1M
^C21+0 records in
21+0 records out
22020096 bytes (22 MB) copied, 21.012 s, 1.0 MB/s
```
此时不用dd命令执行完稍等一下中断执行就能看到速度确实限制在了1Ms。写的同时iostat显示为
```
[zorro@zorrozou-pc0 ~]$ iostat -x 1
Linux 4.3.3-2-ARCH (zorrozou-pc0.tencent.com) 2016年01月15日 _x86_64_ (4 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
0.50 0.00 0.50 25.13 0.00 73.87
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdb 0.00 0.00 0.00 1.00 0.00 1024.00 2048.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 0.00 1.00 0.00 1024.00 2048.00 1.00 1000.00 0.00 1000.00 1000.00 100.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
avg-cpu: %user %nice %system %iowait %steal %idle
1.25 0.00 0.50 24.81 0.00 73.43
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdb 0.00 5.00 0.00 6.00 0.00 1060.00 353.33 0.06 9.33 0.00 9.33 9.50 5.70
dm-0 0.00 0.00 0.00 10.00 0.00 1060.00 212.00 1.08 109.00 0.00 109.00 100.00 100.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
avg-cpu: %user %nice %system %iowait %steal %idle
1.25 0.00 1.00 24.44 0.00 73.32
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdb 0.00 0.00 0.00 1.00 0.00 1024.00 2048.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 0.00 1.00 0.00 1024.00 2048.00 1.00 993.00 0.00 993.00 1000.00 100.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
avg-cpu: %user %nice %system %iowait %steal %idle
1.50 0.25 0.75 24.50 0.00 73.00
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdb 0.00 0.00 0.00 1.00 0.00 1024.00 2048.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 0.00 1.00 0.00 1024.00 2048.00 1.00 1000.00 0.00 1000.00 1000.00 100.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
```
可以看到写的速度确实为1024wkB/s左右。我们再来试试读先创建一个大文件此处没有限速
```
[root@zorrozou-pc0 zorro]# dd if=/dev/zero of=/home/test oflag=direct count=1024 bs=1M
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 10.213 s, 105 MB/s
```
然后进行限速设置并确认:
```
[root@zorrozou-pc0 zorro]# sync
[root@zorrozou-pc0 zorro]# echo 3 > /proc/sys/vm/drop_caches
[root@zorrozou-pc0 zorro]# echo "8:16 1048576" > /sys/fs/cgroup/blkio/test1/blkio.throttle.read_bps_device
[root@zorrozou-pc0 zorro]# cgexec -g blkio:test1 dd if=/home/test of=/dev/null iflag=direct count=1024 bs=1M
^C15+0 records in
14+0 records out
14680064 bytes (15 MB) copied, 15.0032 s, 978 kB/s
```
iostat结果
```
avg-cpu: %user %nice %system %iowait %steal %idle
0.75 0.00 0.75 24.63 0.00 73.88
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdb 0.00 0.00 2.00 0.00 1024.00 0.00 1024.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 2.00 0.00 1024.00 0.00 1024.00 1.65 825.00 825.00 0.00 500.00 100.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
avg-cpu: %user %nice %system %iowait %steal %idle
0.75 0.00 0.50 24.87 0.00 73.87
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 2.00 0.00 2.00 0.00 16.00 16.00 0.02 10.00 0.00 10.00 10.00 2.00
sdb 0.00 0.00 2.00 0.00 1024.00 0.00 1024.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 2.00 0.00 1024.00 0.00 1024.00 1.65 825.00 825.00 0.00 500.00 100.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
```
最后是iops的限制我就不废话了直接上命令执行结果
```
[root@zorrozou-pc0 zorro]# echo "8:16 20" > /sys/fs/cgroup/blkio/test1/blkio.throttle.write_iops_device
[root@zorrozou-pc0 zorro]# rm /home/test
[root@zorrozou-pc0 zorro]# sync
[root@zorrozou-pc0 zorro]# echo 3 > /proc/sys/vm/drop_caches
[root@zorrozou-pc0 zorro]# cgexec -g blkio:test1 dd if=/dev/zero of=/home/test oflag=direct count=1024 bs=1M
^C121+0 records in
121+0 records out
126877696 bytes (127 MB) copied, 12.0576 s, 10.5 MB/s
[zorro@zorrozou-pc0 ~]$ iostat -x 1
avg-cpu: %user %nice %system %iowait %steal %idle
0.50 0.00 0.25 24.81 0.00 74.44
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdb 0.00 0.00 0.00 20.00 0.00 10240.00 1024.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 0.00 20.00 0.00 10240.00 1024.00 2.00 100.00 0.00 100.00 50.00 100.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
avg-cpu: %user %nice %system %iowait %steal %idle
0.75 0.00 0.25 24.31 0.00 74.69
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdb 0.00 0.00 0.00 20.00 0.00 10240.00 1024.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 0.00 20.00 0.00 10240.00 1024.00 2.00 100.00 0.00 100.00 50.00 100.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-3 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
```
iops的读限制我就不在废话了大家可以自己做实验测试一下。
## 其他相关文件
### 针对权重比例限制的相关文件
**blkio.leaf_weight[_device]**
其意义等同于blkio.weight[_device]主要表示当本cgroup中有子cgroup的时候本cgroup的进程和子cgroup中的进程所分配的资源比例是怎么样的。举个例子说吧假设有一组cgroups的关系是这样的
```
root
/ | \
A B leaf
400 200 200
```
leaf就表示root组下的进程所占io资源的比例。 此时A组中的进程可以占用的比例为400/400+200+200 100% 50% B为200/400+200+200 100% 25% 而root下的进程为200/400+200+200 100% 25%
**blkio.time**
统计相关设备的分配给本组的io处理时间单位为ms。权重就是依据此时间比例进行分配的。
**blkio.sectors**
统计本cgroup对设备的读写扇区个数。
**blkio.io_service_bytes**
统计本cgroup对设备的读写字节个数。
**blkio.io_serviced**
统计本cgroup对设备的读写操作个数。
**blkio.io_service_time**
统计本cgroup对设备的各种操作时间。时间单位是ns。
**blkio.io_wait_time**
统计本cgroup对设备的各种操作的等待时间。时间单位是ns。
**blkio.io_merged**
统计本cgroup对设备的各种操作的合并处理次数。
**blkio.io_queued**
统计本cgroup对设备的各种操作的当前正在排队的请求个数。
**blkio.\*_recursive**
这一堆文件是相对应的不带_recursive的文件的递归显示版本所谓递归的意思就是它会显示出包括本cgroup在内的衍生cgroup的所有信息的总和。
### 针对带宽和iops限制的相关文件
**blkio.throttle.io_serviced**
统计本cgroup对设备的读写操作个数。
**blkio.throttle.io_service_bytes**
统计本cgroup对设备的读写字节个数。
**blkio.reset_stats**
对本文件写入一个int可以对以上所有文件的值置零重新开始累计。
## 最后
其实一直纠结要不要写这部分IO隔离的文档因为看上去意义不大。一则因为目前IO隔离似乎工作场景里用的不多二则因为目前内核中这部分代码还在进行较大变化的调整还要继续加入其它功能。从内核Linux 3.16版本之后cgroup调整方向开始了基于unified hierarchy架构的cgroup v2。IO部分在write-back部分进行了较大调整加入了对buffered IO的资源限制。我们这次系统环境为ArchLinux内核版本为Linux 4.3.3虽然环境中的unified hierarchy的开发版本功能已经部分支持了但是思考再三还是暂时不加入到此文档中。新架构的cgoup v2预计会跟随Linux 4.5一起推出,到时候我们再做详细分析好了。
> 原文链接https://zorro.gitbooks.io/poor-zorro-s-linux-book/content/cgroup-linuxde-io-zi-yuan-ge-li.html