bufferio限速

一. 背景
  • cgroup v1目前是每个层级对应一个子系统,每个子系统之间相互独立,各系统之间很难协同工作,blkcg和memcg能分别控制某个进程的资源使用量,但是blkcg 对进程资源限制的时候无法感知 memcg中进程资源的使用量,因此对bufferio的限制一直没有实现。

  • 为解决这一问题,openeuler提供了一种方案,在memcg中增加一个成员struct list_head memcg_node;用于指向与memcg关联的blkcg,在blkcg中增加一个成员struct list_head memcg_list;表示指向此blkcg中的所有memcg。系统启动后可以在用户态手动指定blkcg和memcg的映射关系来实现blkcg和memcg的绑定。

  • 目前我们不希望在用户态手动实现blkcg和memcg的绑定关系,最好能在内核态就实现这种绑定关系。

二. blkcg和memcg内核态绑定设置

阿里提供了一种自动绑定方案,维护一个Radix Trie*memcg_blkcg_tree类型的数据结构来存储所有cgroup的memcg和blkcg的映射关系, 在不同的时机点对树进行增删查的操作。因此我们我们以华为方案为基,参考阿里的方案。在memcg_blkcg_tree插入节点的时机点更新memcg_node和memcg_list。以实现memcg和blkcg的绑定。

static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
{
	struct cgroup_taskset *tset = &mgctx->tset;
	struct cgroup_subsys *ss;
	struct task_struct *task, *tmp_task;
	struct css_set *cset, *tmp_cset;
	int ssid, failed_ssid, ret;

	/* check that we can legitimately attach to the cgroup */
	if (tset->nr_tasks) {
		do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
			if (ss->can_attach) {
				tset->ssid = ssid;
				ret = ss->can_attach(tset);
				if (ret) {
					failed_ssid = ssid;
					goto out_cancel_attach;
				}
			}
		} while_each_subsys_mask();
	}

	/*
	 * Now that we're guaranteed success, proceed to move all tasks to
	 * the new cgroup.  There are no failure cases after here, so this
	 * is the commit point.
	 */
	spin_lock_irq(&css_set_lock);
	list_for_each_entry(cset, &tset->src_csets, mg_node) {
		list_for_each_entry_safe(task, tmp_task, &cset->mg_tasks, cg_list) {
			struct css_set *from_cset = task_css_set(task);
			struct css_set *to_cset = cset->mg_dst_cset;

			get_css_set(to_cset);
			to_cset->nr_tasks++;
			css_set_move_task(task, from_cset, to_cset, true);
			from_cset->nr_tasks--;
			/*
			 * If the source or destination cgroup is frozen,
			 * the task might require to change its state.
			 */
			cgroup_freezer_migrate_task(task, from_cset->dfl_cgrp,
						    to_cset->dfl_cgrp);
			put_css_set_locked(from_cset);

		}
	}
	spin_unlock_irq(&css_set_lock);

	/*
	 * Migration is committed, all target tasks are now on dst_csets.
	 * Nothing is sensitive to fork() after this point.  Notify
	 * controllers that migration is complete.
	 */
	tset->csets = &tset->dst_csets;

	if (tset->nr_tasks) {
		do_each_subsys_mask(ss, ssid, mgctx->ss_mask) {
			if (ss->attach) {
				tset->ssid = ssid;
				ss->attach(tset);
			}
			if (sysctl_bind_memcg_blkcg_enable) {
				list_for_each_entry(cset, &tset->dst_csets, mg_node)
					bind_memcg_blkcg_link(ss, cset);
			}
		} while_each_subsys_mask();
	}
void bind_memcg_blkcg_link(struct cgroup_subsys *ss,
			     struct css_set *cset)
{
	struct cgroup_subsys_state *blkcg_css;
	struct cgroup_subsys_state *memcg_css;

	if (!cgroup1_writeback_enabled())
		return;
	if (ss->id != io_cgrp_id && ss->id != memory_cgrp_id)
		return;
	memcg_css = cset->subsys[memory_cgrp_id];
	blkcg_css = cset->subsys[io_cgrp_id];
	if (!memcg_css || !blkcg_css)
		return;
	if ((memcg_css == &root_mem_cgroup->css) ||
	    (blkcg_css == blkcg_root_css))
		return;
	if (IS_ERR(blkcg_css->cgroup))
		return;
	wb_attach_memcg_to_blkcg(memcg_css, blkcg_css);
}
三 方案安全性

该方案只是对华为和阿里的方案进行整合,改动不大。并且提供了特性启动的开关,可以根据需要来选择是否开启。提供了bind_memcg_blkcg_enable开关来在运行时动态关闭绑定特性

四 测试

1. 起一个docker

2. docker相关的memcg信息和blkcg信息在/sys/fs/cgroup/memory/docker 和 /sys/fs/cgroup/blkio/docker

3. 对写入的设备限速

 echo 253:0 209715200 > /sys/fs/cgroup/blkio/docker/{$docker_id}/blkio.throttle.write_bps_device
 253:0为设备号,lsblk之后可以看到

4. 测速

docker中运行
dd if=/dev/zero of=./testfile bs=4k count=10000
本地运行
iostat -xz 1 vda

可以看到,限速成功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值