-
Notifications
You must be signed in to change notification settings - Fork 95
cgroup writeback v1 interface
Aliyun Linux Kernel 在 alk-release-12 版本(内核版本 4.19.36-12.al7.x86_64
)开始支持 cgroup writeback v1. 即用户在使用 cgroup v1 接口时,也可以对 buffer IO 进行限速。
该功能默认关闭,用户需显式在 grub 里添加 **cgwb_v1 **字段方可开启。
sudo grubby --update-kernel="/boot/vmlinuz-4.19.36-12.al7.x86_64" --args="cgwb_v1"
sudo reboot
系统启动之后,读取 /proc/cmdline
, 确保 cmdline 中带有 cgwb_v1:
cat /proc/cmdline | grep cgwb_v1
此时,blkcg 下的 blkio.throttle.write_bps_device
及 blkio.throttle.write_iops_device
就可以用于限制 buffer IO.
cgroup writeback 需要内存子系统和 IO 子系统协作来完成 buffer IO 的限速,但是 cgroup v1 接口各个控制子系统没有默认协同工作,因此需要通过一定的规则把 memory 子系统和 blkio 子系统链接起来,原则就是通过任意一个 memcg 必可找到与之唯一对应的 blkcg. 换言之,假设存在有进程 A 和 B,想要对它们进行 buffer IO 限速,我们需遵循如下限制约束:
- 如果 A 和 B 分属不同的 memcg, 那么它们可以分别映射到不同的 blkcg,只需各自一一对应。e.g.: A 属于
memcg1
,blkcg1
; B 属于memcg2
,blkcg0
; - 如果 A 和 B 分属不同的 memcg, 显而易见它们也可以映射到同一个 blkcg. e.g.: A 属于
memcg1
, B 属于memcg2
, 它们都属于blkcg2
; - 如果 A 和 B 属于相同的 memcg,那么它们只能映射到同一个 blkcg. e.g.: A & B 均属于
memcg0
, 它们同时属于blkcg3
.
显而易见,我们可以将以上约束概括成要点:memcg 与 blkcg 的映射,可以是 1 对 1,可以是 N 对 1,不可以是 1 对 N 或是 M 对 N. 为了避免意外地制造 1 对 N 或者 M 对 N 映射,我们推荐先设置 blkcg 的 cgroup.procs
接口,再设置 memcg 的。
在运维上,可能会出现一种会打破 1 对 1 或者 N 对 1 的正确映射的情况,即进程移动到其他 cgroup 的情况。根据映射原则,我们可以知道,如果进程在 memcg 之间移动,是没有问题的;但如果进程在 blkcg 之间移动,就会出现 1 对 N 或者 M 对 N 的情况。举例如下:
进程 A 属于 memcg1
, 进程 B 属于 memcg2
,原本都映射到 blkcg2
中,后来由于运维操作,将进程 B 从 blkcg2
移动到了 blkcg20
中。由于可能会有未完成的 writeback 存在,因此 blkcg 的移动这个过程,可能会让 memcg2
中未完成的 writeback 不知道该对应查找 blkcg2
还是 blkcg20
的规则,从而造成混乱。
为了避免此种情况,我们在代码中定义了如下逻辑:
一旦工作中的 blkcg 内的进程发生 blkcg 间移动,则将映射关系直接指向 root blkcg。
由此,在上述的例子中,如果进程 B 从 blkcg2
移动到 blkcg20
,则 memcg2
对应的映射关系直接更改为 root blkcg
。
由于我们一般不在 root blkcg
设置 blkio.throttle 值,所以限速功能此时也一般会失效。因此需要尽量避免将进程在 blkcg 间移动。
# cat /sys/kernel/debug/bdi/bdi_wb_link
memory <---> blkio
test: 35 <---> root: 1
1:173059 <---> 1: 275
2:173443 <---> 1: 275
3:174755 <---> 1: 275
echo 1 > /sys/kernel/debug/tracing/events/writeback/insert_memcg_blkcg_link/enable
cat /sys/kernel/debug/tracing/trace_pipe
我们一般会用不带 oflag=sync 的 dd 命令来产生异步 IO 以检验 cgroup_writeback 功能是否有效,请注意由于 dd 异步 IO 反馈速度较快,正确的方式应该通过 iostat 来查看。
此外,由于 dd 写入为顺序写,由于 ext4 的 bio 初始化是按照 BIO_MAX_PAGES
(256 pages) 来的,所以顺序 IO 回刷时,会先攒成1M大小 (4k x 256) 再刷下去。此时如果 blkio.throttle.write_bps_device
设置小于 1M (1048576),会造成一个单独的 IO 都无法完成回刷,从而触发 IO Hang. 正确的做法是,在设置阈值时 write_bps 不要设置为小于 1M.