Контейнерная виртуализация Cell/B.E. : Часть 2. Вопросы реализации

Представляем принципы программной контейнерной виртуализации на платформе Cell/B.E. с использованием проекта с открытым исходным кодом OpenVZ

В этой серии из трёх частей представлена форма программной виртуализации, ориентированная на аппаратные ресурсы, известная как контейнерная виртуализация (или виртуализация операционной системы), для демонстрации которой используется проект с открытым исходным кодом OpenVZ. В серии представлен исчерпывающий обзор всех компонентов и методик, необходимых для виртуализации процессора Cell/B.E. программными методами. Эта статья, вторая в серии, подробно описывает реализацию выделенной виртуализации и разбиения на разделы, описанных в первой части серии..

Кристиан Кайзер, Стажёр, IBM

Кристиан Кайзер (Christian Kaiser) изучает вычислительную технику в университете RWTH в Ахене в Германии. В 2007 году он проходил стажировку в исследовательской лаборатории IBM в Германии, в городе Бёблинген. Во время стажировки в IBM он исследовал методы виртуализации для процессора Cell Broadband Engine. После завершения стажировки Кристиан Кайзер начал работу над диссертацией на кафедре операционных систем в университете RWTH в Ахене. Тема его диссертации - "Анализ коллективной асинхронной связи в высокоскоростных сетях, организованных в памяти"



Кристиан Рунд, исследователь-разработчик, IBM

Кристиан Рунд (Christian Rund) - сотрудник исследовательской лаборатории IBM в Бёблингене, в Германии. Он изучал теорию вычислительных систем в университете Штутгарта и в Упсальском университете в Швеции, закончив обучение в 1997 году. Во время учебы он проходил стажировку в IBM в Херренберге и Штутгарте в Германии. В 1998 году он поступил на работу в департамент разработки систем банка Landeszentralbank в Штутгарте (Deutsche Bundesbank). В 2001 году Кристиан перешел в команду разработчиков канала FCP zSeries корпорации IBM в качестве исследователя-разработчика. С середины 2006 года он занимается исследованием и разработкой микропрограммного обеспечения хост-контроллера Cell/B.E.



12.02.2008

В статье описывается реализация понятия выделенной виртуализации (разбиения на разделы), показанного в первой статье (часть 1, рисунок 3). В этой статье не рассматривается концепция устройств общего пользования (показанная в части 1, на рисунке 4).

Чтобы продемонстрировать реализацию системы, в этой статье будут освещены следующие вопросы:

  • Виртуализация spufs: предотвращение использования одного root-inode для всех точек монтирования
  • Корректировки sysfs: записи необходимо корректировать в реальном времени
  • Модификация планировщика SPU: добавление шага реализации виртуализации
  • Модификация инструментов OpenVZ: использование новых функций

Виртуализация spufs

По умолчанию spufs использует один и тот же root-inode при каждом монтировании. Например, у вас может быть две среды chroot (A и B), и spufs обоих будет смонтирована по пути /spu. Если вы создадите потоки SPE в среде A, после чего выведете содержимое /spu, вы увидите только что созданные потоки SPE. Однако в среде B вы увидите тот же листинг /spu, поскольку вы обращаетесь к тому же root-inode, что и в среде A.

Чтобы изменить такое поведение, т.е. чтобы в обеих средах можно было увидеть только созданные в них потоки SPE, необходимо изменить тот факт, что spufs всегда использует один и тот же root-inode для всех точек монтирования. При монтировании spufs она вызывает функцию ядра, которая возвращает системный блок. Обычно используется функция get_sb_single(), которая всегда возвращает один и тот же системный блок. Функция get_sb_nodev() всегда возвращает различные системные блоки, что приводит к нужному нам результату. (На рисунке 1 показана spufs до и после выполнения виртуализации.)

Рисунок 1. Spufs до и после выполнения виртуализации
Spufs до и после выполнения виртуализации

OpenVZ позволяет смонтировать внутри контейнера только несколько файловых систем. Каждая система реализует экземпляр struct file_system_type , который определяет аспекты, связанные с файлами. OpenVZ расширяет эту структуру (наряду с другими), дополняя ее компонентом, определяющим, может ли быть смонтирована файловая система. Таким образом, компоненту .fs_flags должно быть установлено значение FS_VIRTUALIZED.

У процесса, созданного внутри контейнера, есть два PID. (Вспомните часть 1 , в которой говорилось, что у каждого контейнера есть собственное множество ресурсов, предоставляемых ядром. У дерева процессов было одно множество ресурсов, а контейнер мог видеть только собственное множество процессов с виртуализованными PID.) Внутри контейнера есть виртуализованный PID, а в базовой системе тот же процесс идентифицируется другим PID, который называется глобальным PID. Как уже упоминалось, название директорий spufs задаётся в виде spethread-<PID>-<thread-ID>, где <PID> - идентификатор процесса потока SPE, а <thread-ID>> соответствующий идентификатор потока. Поскольку в среде контейнера используются виртуализованные PID, листинг spufs внутри контейнера должен показывать виртуализованные, а не глобальные PID. К счастью, такой алгоритм уже реализован в OpenVZ.

Измените файл arch/powerpc/platforms/cell/spufs/inode.c в ядре Linux®.


Корректировка sysfs

sysfs уже виртуализована, поэтому ее можно использовать внутри контейнеров. Она является не копией sysfs, видимой в базовой системе, а её частью. Цель состоит в том, чтобы выделять SPU контейнерам и освобождать их в реальном времени. Это означает, что записи sysfs также необходимо адаптировать в реальном времени. Перед этим создайте директорию, в которой перечислены SPU.

Это директория /sys/devices/system/spu. По умолчанию в sysfs в среде контейнера нет директорий /sys/devices/system/spu, /sys/devices/system и /sys/devices. Эти три записи необходимо создать во время инициализации (запуска) контейнера. Поддиректории /sys/devices/system/spu могут иметь вид от spu0 до spu<N>, где <N> - количество доступных SPU в системе минус 1. Директории необходимо создавать, когда SPU назначается контейнеру, и удалять, когда они открепляются от контейнера.

Каждой директории в листинге sysfs должен соответствовать экземпляр kobject в пространстве ядра. kobject - это структура, которая определяет название директории и её родительский kobject (другими словами, соответствующую родительскую директорию). Например, у kobject, который отображается как директория /sys/devices/system/spu/spu3, есть два параметра, которые нужно изменить:

  • Название spu3.
  • Родитель (указатель на kobject, представляющий /sys/devices/system/spu).

После регистрации kobject в sysfs посредством вызова subsystem_register(), он становится видимым из пространства пользователя. Обратное действие состоит в удалении директории из sysfs. Для этого можно вызвать функцию subsystem_unregister(), указав kobject, который необходимо удалить. На рисунке 2 показан пример.

Рисунок 2. Sysfs и kobjects
Sysfs и kobjects

У kobject с названием spu3 есть указатель на родительский kobject с названием spu.

Основные изменения необходимо сделать в файле ядра kernel/ve/vecalls.c. Это файл OpenVZ, в котором реализовано большинство функций, которые вызываются во время инициализации и настройки параметров контейнеров.


Модификация планировщика SPU

Каждый физический SPU системы представлен экземпляром структуры spu в пространстве ядра. В этой структуре хранится несколько параметров, в число которых входят:

  • Идентификатор (номер) SPU
  • К какому узлу Cell/B.E. он принадлежит
  • Указатель на LS SPU

Новая переменная хранит владельца SPU в виде идентификатора контейнера. Планировщик SPU реализует функцию spu_alloc(), которая ищет свободный SPU, на котором будет выполняться поток SPE. Таким образом, он ищет список доступных в системе SPU (на которых в данный момент не выполняется потоков SPE).

Обычно берется первый SPU в списке и на нём запускается поток SPE. Чтобы реализовать виртуализацию, функция должна проверить, совпадает ли идентификатор контейнера свободного SPU с идентификатором контейнера потока SPE, который предполагается на нем выполнить. На рисунке 3 показано, как работает spu_alloc() до и после модификации.

Рисунок 3. Spu_alloc() до и после модификации
Spu_alloc() до и после модификации

Если эта дополнительная проверка дает негативный результат, функция проверяет следующий элемент в списке свободных SPU. Если свободных SPU для контейнера, запускающего поток SPE, нет, планировщик SPU ведет себя так же, как если бы список был пуст, и ждёт освобождения SPU.

Функция spu_alloc() реализована в исходном файле ядра Linux arch/powerpc/platforms/cell/spu_base.c.


Модификация инструментов OpenVZ

Большая часть нужной функциональности уже реализована, но для того, чтобы использовать новые функции, необходимо модифицировать инструменты OpenVZ. Инструмент vzctl управляет выделением SPU в реальном времени. Это основной инструмент для настройки параметров в OpenVZ. Новый параметр для установки количества SPU, выделенных контейнеру, - --spus <nr_spus>.

Значение <nr_spus> представляет количество SPU, выделенных контейнеру. Это абсолютное значение, поэтому если контейнеру с восемью SPU присваивается значение 6, то от процессора открепляются 2 SPU, а не добавляются 6 SPU (8 - 6 = 2).

Например, вот результат работы команды, когда контейнер с ID, равным 101, получает восемь SPU:

[root@c02b12-0 ~]# vzctl set 101 --spus 8
Setting SPUs: 8
Configure meminfo: 1024000
WARNING: Settings were not saved and will be reset to original
 values on next start (use --save flag)
[root@c02b12-0 ~]#

Для реализации такого алгоритма инструмент vzctl должен перейти барьер пространства пользователя и выполнить ряд операций управления в пространстве ядра. Инструмент должен найти SPU, которые не используются другими контейнерами. Инструмент vzctl выполняет поиск по списку доступных SPU и проверяет идентификатор контейнера в структуре нового spu (описана в разделе модификации планировщика SPU). Если это значение равно 0, SPU может быть назначен рассматриваемому контейнеру. Значение 0 используется потому, что значение идентификатора контейнера должно быть больше 0, т.е. значение 0 указывает на то, что SPU не назначен ни одному из контейнеров. Если функция не может найти нужного для выполнения запроса количества свободных SPU, процедура завершается и не назначает контейнеру ни одного SPU. Если количество SPU, уже назначенных контейнеру, больше запрошенного количества SPU, разница открепляется.

Чтобы преодолеть барьер между пространством пользователя и пространством ядра, можно использовать различные модели реализации. (Дополнительную информацию о моделях реализации можно найти в статье Арнда Бергмана "Как не изобрести интерфейсы ядра", ссылка на которую приведена в разделе Ресурсы.) Наиболее простой способ состоит в реализации нового системного вызова, который накладывает параметры <containerID> и <nr_spus> на параметры системного вызова.

Функции, которые выполняют настройку параметров SPU контейнера, должны реализовываться в той части ядра, которая может быть реализована в модуле ядра. Это представляет большую проблему. Если модуль ядра не загружен, функция обработки системного вызова в пространстве ядра ничего не сделает. Однако если модуль загружен, он вызовет функцию, реализованную в модуле. Это нетривиальная задача, поскольку таблица системных вызовов (где хранятся указатели функции на функции обработки системных вызовов) является частью статической сборки ядра.

Модуль не является частью этой статической функции, и поэтому статическая встроенная функция обработки системного вызова не может вызвать функцию, являющуюся частью модуля. Решение состоит в реализации оболочки функции, которая копирует указатель на функции модуля в переменную встроенной статической функции обработки системного вызова таким образом, чтобы встроенный статический обработчик системного вызова мог вызвать функцию модуля. Эта оболочка функции вызывается во время инициализации и очистки модуля. Чёрная стрелка на рисунке 4 показывает наш метод оболочки функции.

Рисунок 4. Функции модуля и системный вызов
Функции модуля и системный вызов

Вы видите, как указатель функции, реализованной в модуле, копируется во встроенную статическую функцию пространства ядра. Пунктирные стрелки показывают, как приложения пространства пользователя вызывают функцию модуля, передавая встроенную статическую функцию обработчика системного вызова.

Необходимо изменить исходный код ядра в следующих файлах:

  • include/asm-powerpc/systbl.h
  • include/asm-powerpc/unistd.h
  • include/linux/syscalls.h
  • kernel/sys.c
  • kernel/sys_ni.c
  • kernel/ve/vecalls.c

Кроме того, обновляются файлы исходного кода vzctl OpenVZ:

  • include/res.h
  • include/vzctl_param.h
  • include/vzsyscalls.h
  • src/lib/config.c
  • src/lib/res.c
  • src/vzctl.c

В систему сборки OpenVZ добавляется два новых файла:

  • include/spu.h
  • src/lib/spu.c

Подготовка к третьей части

В третьей части серии описывается использование и тестирование системы, а также приводится анализ производительности контейнерной виртуализации по сравнению с другими программными методами виртуализации – в частности, паравиртуализацией и полной виртуализацией.

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux, Open source
ArticleID=288677
ArticleTitle=Контейнерная виртуализация Cell/B.E. : Часть 2. Вопросы реализации
publish-date=02122008