В современных серверах стандартной архитектуры, построенных на базе многоядерных микропроцессоров, число логических процессоров сопоставимо с числом процессоров больших Unix-серверов недавнего прошлого. В связи с тем, что популярная для серверов стандартной архитектуры ОС Linux эффективно работает также и на многопроцессорных системах с общей памятью суперкомпьютерного уровня, естественно, что развитые средства управления ресурсами — cgroups (соntrol groups, контрольные группы) — появились и в стандартных ядрах Linux (начиная с 2.6.24). Современные версии ядер и соответствующие дистрибутивы Linux по умолчанию включают в свои конфигурации поддержку cgroups — не стала исключением и версия ОС OpenSuSE 12.1 c ядром 3.1.0, на примере которой покажем особенности работы с контрольными группами.

Контрольная группа — это множество задач (task), характеризующихся определенным набором параметров подсистем. К контрольным группам принадлежат не только исходно приписанные к ним задачи, но и все их «потомки». Применение контрольных групп позволяет управлять распределением различных ресурсов, доступных ОС, между группами процессов. Подсистема — средство предоставления задачам некоторого сервиса. Типичной подсистемой является контроллер каких-либо ресурсов (процессор, память и т. д.), но подсистема может предоставлять, например, услуги по изоляции процессов в пространстве имен. Взаимодействие контрольных групп с подсистемами осуществляется путем установки настраиваемых параметров подсистем для каждой контрольной группы.

Подобно процессам, cgroups организованы иерархически, что отражается деревом соответствующих каталогов в файловой системе cgroup. Дочерние группы наследуют атрибуты родителей. Иерархия cgroups может ассоциироваться с несколькими или со всеми подсистемами, но может быть и так, что каждой подсистеме отвечает своя иерархия. Если подсистема задействована в управлении какой-либо иерархией (см. рисунок), то она не может применяться в других иерархиях. Каждой иерархии принадлежит часть всех задач ОС. В данной иерархии задача может принадлежать только одной контрольной группе, но одна и та же задача может быть представлена в контрольной группе, управляемой одним набором подсистем, и в другой контрольной группе из другой иерархии, управляемой другим набором подсистем.

 

Иллюстрация взаимосвязи контрольных групп, подсистем и задач. Представлены две иерархии (А и B), семь подсистем (подсистема 6 не задействована в cgroups) и четыре задачи

Иллюстрация взаимосвязи контрольных групп, подсистем и задач. Представлены две иерархии (А и B), семь подсистем (подсистема 6 не задействована в cgroups) и четыре задачи

 

В стандартной версии ядра OpenSuSE 12.1 представлено девять подсистем. Параметры подсистем, которые управляют контрольными группами, устанавливаются путем записи значений этих параметров в соответствующие псевдофайлы виртуальной файловой системы cgroup.

Подсистема cpuset позволяет «привязать» задачи к определенному набору логических процессоров (это могут быть ядра многоядерных микропроцессоров или логические процессоры в случае применения технологий многонитевой обработки, например Intel HyperThreading). Можно не только указать, на каких процессорах будет выполняться задача (файл cpuset.cpus), но и какими узлами оперативной памяти они могут пользоваться (файл cpuset.mems). В современных микропроцессорах контроллеры памяти встроены, что приводит многопроцессорные серверы к архитектуре ccNUMA, когда имеется отличие между локальной памятью (узлом), подсоединенной напрямую к данному процессору, и удаленной памятью, подсоединенной к другим процессорам.

Подсистемы cpu и cpuacct выполняют две главные функции: учет использования процессорного времени и ограничение доли процессорного времени, на которое может претендовать контрольная группа (все ее задачи вместе). Подсистема memory позволяет ограничивать память, которую разрешается использовать задачам контрольных групп. Подсистема devices позволяет системному администратору указать список устройств, к которым будут иметь доступ задачи контрольной группы. Подсистема blkio (блочный ввод/вывод) является контроллером ресурсов дискового ввода/вывода. С ее помощью можно сформулировать политику распределения полосы пропускания ввода/вывода, указав пропорциональные веса. Подсистема freezer ориентирована на применение в высокопроизводительных кластерах и предназначена для остановки («заморозки») всех задач в группе — например, если они достигли контрольной точки. Подсистема net_cls позволяет приписывать идентификаторы сетевым пакетам, что может применяться для указания приоритетов пакетам, используемым задачами разных групп.

Пусть имеется университетский сервер, на котором выполняются задачи преподавателей и студентов, а также системные задачи. Можно задать условие, чтобы системные задачи задействовали до 20% процессорного времени, задачи преподавателей — до 60%, а студенческие — до 20%, причем если логических процессоров много, то возможно выделить каждой группе собственные процессоры. Можно ввести также ограничения на долю памяти: 20% системе, 50% преподавателям и 30% студентам, а также разграничить полосу пропускания дисковых устройств: 20% системе, 50% преподавателям и 30% студентам. Наконец, можно разграничить сетевой ввод-вывод, отдав 20% для выполнения браузеров, 60% — сетевой файловой системе и 20% — на другие нужды. В свою очередь, можно разграничить и сетевой трафик браузеров. Можно считать системные задачи верхним уровнем иерархии cgroups — cюда попадают все задачи, не запускаемые преподавателями или студентами. А на втором уровне иерархии можно расположить две контрольные группы: для преподавателей и студентов.

Если не брать в расчет задачу разграничения сетевого трафика, то можно сделать так, чтобы все контрольные группы управлялись одним общим набором подсистем, а можно создавать свою иерархию контрольных групп для каждой подсистемы. В последнем случае каждая задача на сервере будет попадать сразу в три разные контрольные группы — по одной в каждой иерархии. В разных версиях ядер могут быть, вообще говоря, реализованы разные подсистемы. Например, в стандартном ядре дистрибутива OpenSuSE 12.1 не поддерживаются средства управления пропускной способностью сетевого ввода/вывода. В случае реализации в ядре можно было бы создать три контрольные группы: для браузеров, NFS и других процессов. При этом контрольная группа для браузеров состояла бы из двух подгрупп — для преподавателей и студентов, и все такие задачи попадали бы исключительно в одну из этих подгрупп. Можно было бы также создавать свои подгруппы для каждого типа браузеров.

Базовые cредства cgroups реализованы в ядре, однако для удобства работы администратора по управлению ресурсами сервера имеются дополнительные пакеты, в частности, обеспечивающие возможности управления cgroups более высокого уровня. В OpenSuSE эти средства находятся в rpm-пакетах cpuset, libcgroup1, libcpuset1 и lxc. Все эти пакеты отсутствуют в стандартном дистрибутиве OpenSuSE 12.1 — их надо установить отдельно, как и пакеты libbitmask1 и libcap-progs, необходимые для libcpuset1 и lxc соответственно. Далее рассмотрим только пакет libcgroup1, который непосредственно связан с cgroups.

Если не применять специальные утилиты, то для работы с cgroups можно использовать базовые средства Linux, смонтировав виртуальную файловую систему tmpfs:

mount -t tmpfs name /куда/монтировать,

где name — метка, с которой монтируется tmpfs. Далее нужно смонтировать виртуальную файловую систему типа cgroup, указав в параметре -o команды mount список имен подсистем, которые будут приписаны иерархии контрольных групп:

mount -t cgroup -o список_имен_подсистем имя /куда/монтировать/имя,

где произвольное имя задает название иерархии групп.

При создании контрольной группы просто формируются соответствующие подкаталоги, поэтому для создания подгрупп в данной иерархии можно воспользоваться обычной командой mkdir. В случае OpenSuSE 12.1 для создания иерархии cgroups достаточно просто выполнить каманду создания иерархии mycgroup:

mkdir /sys/fs/cgroup/cpuset/mycgroup.

При выполнении mkdir в каталоге автоматически создаются псевдофайлы, содержимое которых используется для установки значений параметров подсистем. Строго говоря, иерархия начинается с каталога /куда/монтировать/имя, или конкретно в нашем случае — с /sys/fs/cgroup/cpuset, поскольку там также имеется набор псевдофайлов для параметров. Имена псевдофайлов имеют вид имя.параметр_подсистемы, где имя задает подсистему, поэтому у разных подсистем имена псевдофайлов всегда различаются. Для того чтобы установить конкретные параметры для контрольной группы, нужно просто произвести запись в псевдофайлы соответствующего каталога. Например, последовательность типа:

cd /sys/fs/cgroup/cpuset/mycgroup

echo 2-3 > cpuset.cpus

echo 1 > cpuset.mems

разрешит этой группе использовать только логические процессоры 2, 3 и узел 1 оперативной памяти. Теперь для того чтобы процесс с идентификатором myPID был приписан к данной контрольной группе, нужно выполнить echo myPID > tasks.

Для создания контрольной группы используется команда

cgcreate -g имя_подсистемы:путь.

Например, сgcreate — g cpuset:mycgroup эквивалентна команде mkdir для создания контрольной группы mycgroup.

Команда сgclassify -g имя_подсистемы: путь список_PID

позволяет приписать существующие процессы с идентификаторами из списка PID (идентификаторы в нем разделяются пробелами) cоответствующей контрольной группе (эти идентификаторы прописываются в псевдофайле tasks). Для того чтобы с самого начала выполнять команду (запускать задачу) в определенных контрольных группах, применяется

cgexec -g имя_подсистемы:путь команда [аргументы].

Программы cgconfigparser и демон cgrulesengd (Cgroup Rules Engine Daemon) предоставляют средства для работы с cgroups высокого уровня. Первая обеспечивает построение и настройку иерархий контрольных групп, а вторая отвечает за определение в соответствии с заданными правилами идентификаторов процессов, которые будут отнесены к нужным контрольным группам. Утилита сgconfigparser использует конфигурационный файл /etc/cgconfig.conf, в котором определяются контрольные группы, их точки монтирования и параметры подсистем, управляющих контрольной группой. Конфигурационный файл cgrules.conf демона cgrulesengd состоит из двух типов секций, mount и group. В секции mount указываются подсистемы, управляющие контрольными группами, и точка монтировки иерархии контрольных групп.

Рассмотрим пример с созданием контрольной группы mycgroup, управляемой подсистемой cpuset в каталоге /mnt/cgroups. Для этого понадобится такой файл config.conf:

mount {cpuset = /mnt/cgroups/cpuset;}

group mycgroup {

          perm {

             task {uid = guest; gid = users;}

             admin {uid = root;gid = root;}

               }

             cpuset {cpuset.cpus = 2;cpuset.mems = 1;}

             }

Здесь задачам группы mycgroup разрешено выполняться только на логическом процессоре 2 и узле памяти 1, а файлом tasks будет владеть только пользователь guest из группы users.

Выполнение cgconfigparser создаст нужные контрольные группы с нужными параметрами подсистем. Но приписывать процессы к группе может понадобиться динамически, по мере их возникновения, поэтому необходим демон, отслеживающий процессы и отбирающий из них нужные. Такая работа реализуется демоном cgrulesengd, конфигурационный файл которого /etc/cgred.conf управляет общими параметрами работы, в том числе задает имя файла (полный путь) для протоколирования и уровень подробности.

Михаил Кузьминский (kus@free.net) — старший научный сотрудник Института органической химии им. Н. Д. Зелинского РАН (Москва).