Уже довольно давно в лиуксах используется такая чудная система для ограничения приложений по ресурсам как cgroups. Руки к ней я тянул тоже довольно давно и вот наконец-то я дотянулся до них.

 

Смысл в том, что мне наконец надоело, что либо браузер съедает CPU либо память, либо какое-то приложение (напр. rsync/cp/git) приседает на диск с такой силой, что работать просто невозможно. Соответственно, таки прожорливае программы надо как-то ограничивать. Жёсткие ограничения - это бессмысленно так как если есть простаивающие ресурсы, то почему бы их не передать нуждающемуся приложению, но если оно наглеет и не хочет, например, делиться CPU-шкой с другим приложением - это какбэ не сильно гуманно, должна быть ручка, которая как бы приложение зубами ни упиралось, всё равно легко и беззатейливо могла бы его подвинуть. И ручка такая есть - как раз cgroup для этого и создавалась.

 

Итак, к делу. После долгих забегов по граблям, выяснилось, что для оптимального руления группами нам необходимо:
<ul>
<li>чтобы модуль cn.ko (Connector - unified userspace <-> kernelspace linker) был встроен в ядро иначе будет невозможно находить процессы и автоматически пихать их в нужную cgroup.</li>
<li>Далее, несмотря на то, что cgroup-пы можно монтировать по отдельности: отдельно cpu, отдельно cpuacct, отдельно blkio и тд - для более эффективной работы лучше их смонтировать в одну кучу, напр. в sys/fs/cgroup.</li>
<li>Кроме того, во всех не sysdefault грумппах необходимо задавать cpuset.cpus (это ядра, на которых будут работать процессы в группе) и cpuset.mems (это домены памяти в NUMA-представлении, если система не NUMA, то = 0).</li>
</ul>
Поскольку я на практике использую Slackware Linux, то из каробки у меня есть 2 сервиса - это cgconfig и cgrules(cgred).

В стартовом скрипте для cgconfig пришлось подправить 2 момента: перед в процедуре запуска нужно вызывать останов, на всякий случай, если подсистемы запущены и cgropfs смонтированы (а такое бывает, когда cgroups не модулями, а вкомпилены в ядро) и второй момент - останов cgconfig происходит не полностью, для полного останова (и размонтирования) необходимо разика 3 остановить сервис, соответственно, в скрипте это тоже пришлось подправить.

Кроме того, cn.ko был собран модулем, так что пришлось пересобрать ядро, благо в slackware пересобрать ядро довольно просто :) Заодно выяснилось, что cgred работает на ядрах, по версии ниже чем 3.15, в котором влили какое-то ограничение по количеству процессов, управляющих cgroups, видимо с целью <a href="http://boycottsystemd.org/">привязать ядро и userspace</a> к systemd, там вроде нужно уведомить ядро, какой pid вносит процессы в различные cgroup.

Традиционно, пачка конфигов:

/etc/cgconfig.conf:

mount {
    cpuset = "/sys/fs/cgroup";
    cpu = "/sys/fs/cgroup";
    cpuacct = "/sys/fs/cgroup";
    memory = "/sys/fs/cgroup";
    devices = "/sys/fs/cgroup";
    freezer = "/sys/fs/cgroup";
    net_cls = "/sys/fs/cgroup";
    blkio = "/sys/fs/cgroup";
    perf_event = "/sys/fs/cgroup";
}

group sysdefault {
    cpu {
        cpu.shares = 500;
    }
    blkio {
        blkio.weight = 500;
    }
}

group browser {
    cpu {
        cpu.shares = 100;
    }
    cpuset{
        cpuset.cpus = 0-3;
        cpuset.mems = 0;
    }
    blkio {
        blkio.weight = 200;
    }
}

group io {
    cpu {
        cpu.shares = 250;
    }
    cpuset{
        cpuset.cpus = 0-3;
        cpuset.mems = 0;
    }
    blkio {
        blkio.weight = 100;
    }
}

/etc/cgrules.conf:

*:firefox       cpu,blkio       browser/
*:thunderbird       cpu,blkio       browser/

*:cp            cpu,blkio       io/
*:mv            cpu,blkio       io/
*:svn           cpu,blkio       io/
*:hg            cpu,blkio       io/
*:git           cpu,blkio       io/
*:rsync         cpu,blkio       io/
*:mc            cpu,blkio       io/

 

 

 

Next Post