Антон Борисов
Большую часть времени ПЭВМ, скажем честно, простаивает. Средняя загрузка
не превышает 20%. Но как только начинается сборка приложений, например на C++,
или оцифровка видео-, аудиофайлов, то становится очевидным недостаток
вычислительных ресурсов. Основная идея HPC-кластеров – задействовать ресурсы,
свободные на других узлах кластера.
Что такое кластер
Кластер – это две или более самостоятельные системы, объединенные в единое
целое посредством специального программного и аппаратного обеспечения. Основное
звено кластера – это единичный компьютер, называемый узлом. Кластеры могут
расти – «масштабироваться» – путем добавления новых узлов. При этом
синергетическое целое мощнее, нежели отдельный узел. Изменения в структуре
кластера, например, появление и удаление узлов из состава кластера (по разным
причинам – авария или, наоборот, восстановление после критической ситуации)
фиксируется всеми оставшимися/новыми узлами.
Типы кластеров
На сегодняшний момент широко известны и распространены 3
типа кластеров – отказоустойчивые (например, LifeKeeper – см. [1]), с
балансировкой загрузки (Load-Balancing) и высокопроизводительные (High-Perfomance
Computing):
n Отказоустойчивый кластер состоит из двух или
более узлов, между которыми существует выделенное соединение (heartbeat),
которое используется для обмена служебной информацией между узлами. Как только
какой-либо из узлов перестает функционировать, то второй (резервный) узел берет
его функции на себя.
n Задача кластера с балансировкой нагрузки
заключается в том, чтобы перенаправить запрос, скажем к веб-серверу, к наименее
загруженному в данный момент времени узлу. По существу, этот тип кластера можно
также назвать отказоустойчивым, только с дополнительным функционалом балансировки
и с большим количеством узлов.
n В высокопроизводительном кластере узлы
сконфигурированы таким образом, чтобы общая производительность была
максимальной. В этом типе кластера присутствуют и балансировочные механизмы –
задания распределяются между узлами. Самое интересное в таком типе кластера –
факторизация процесса (разбиение задачи на несколько параллельных подзадач). Процесс
не ожидает освобождения CPU, а запускает свои подзадачи на разных узлах.
Суперкомпьютеры и кластеры
Традиционно ресурсоемкие математические вычисления выполнялись на
суперкомпьютерах. Они выпускались определенным количеством производителей и
организация, которая хотела купить суперкомпьютер, должна была обладать немалым
финансовым ресурсом. Естественно, что большинство университетов не могли себе
позволить такого рода дорогую игрушку, поэтому в их недрах начала создаваться
концепция кластера для академических кругов. Цель данной концепции –
подготовить условия для распараллеливания задачи между узлами, передать
обработку подзадач на узлы и затем собрать результаты каждой подзадачи. Кластер
предполагалось собирать на PC-платформе, благо она становилась всё более и
более распространенным явлением и по сути дешевой.
Кластерные модели
Существует несколько методов распараллеливания – N(UMA),
DSM, PVM и MPI. Некоторые из этих схем реализованы аппаратно, другие
программно. Бывают и смешанные решения:
n (N)UMA ((Non-)Uniform Memory Access) – узлы
имеют доступ к общей памяти, где выполняется код. Стоит отметить, что в
Linux-ядре есть NUMA-реализация.
n DSM (Distributed Shared memory) реализовано как
программно, так и аппаратно. Концепция этого метода заключается в
предоставлении уровня абстракции для физически распределенной памяти.
n MPI (Message Passing Interface, интерфейс
передачи сообщений) – это открытая спецификация для создания библиотек передачи
сообщений. В частности, библиотека MPICH – самое известное решение на базе MPI.
Другое известное решение – библиотека LAM.
n PVM (Parallel Virtual Machine) является
собратом MPI. Фунционирует PVM в пользовательском пространстве, поэтому
каких-то модификаций на уровне ядра не требуется. Пользователь с достаточными
правами может запустить PVM.
Сущность OpenMosix
Пакет OpenMosix – это патчи к ядру Linux. На момент написания этого
материала существуют патчи для ядра 2.4.26 и для ветки 2.6. Так как OpenMosix реализован
в виде патчей, то сохраняется полная совместимость между программами, файлами и
другими ресурсами в Linux.
Обычный пользователь может и не заметить
изменений между Linux-машиной и OpenMosix-кластером, ибо последний будет расматриваться
как рядовая Linux-машина, только немного производительнее. Внутренний механизм
балансировки прозрачно производит миграцию процессов на узлы кластера.
Оптимальная загрузка кластера вычисляется динамически через определенные
промежутки времени. Вы также можете произвести нужную подстройку параметров
кластера. Прозрачный механизм миграции играет интересную роль – из-за него весь
кластер выглядит как большая SMP-машина со множеством процессоров (каждый узел в
роли процессора). В рамках OpenMosix разработана файловая система (oMFS) для
HPC-приложений, которая в отличие от NFS поддерживает целостность ссылок,
атрибуты времени и кеширование.
Сегодня в нашем обзоре в качестве
узлов кластера будут выступать 3 машины:
n Intel(R) Pentium(R) 4 CPU 1.80 ГГц (256 Мб ОЗУ)
n Intel Pentium III (Katmai) 602.149 МГц (256 Мб
ОЗУ)
n Intel(R) Pentium(R) 4 CPU 3.00 ГГц (128 Мб ОЗУ)
Все узлы соединены через хаб (100 МБит) в единое
пространство. Операционная система, OC Linux, первоначально установлена на
самой быстрой машине, а затем была клонирована на все остальные. Стоит
отметить, что при установке, помимо базовых пакетов, также следует выбрать
и QT-библиотеку (на базе QT мы впоследствии соберем утилиты мониторинга
кластера).
Итак, первый шаг по установке и настройке ПЭВМ с
ядром по умолчанию пропускаем. Следует настроить SSH-сервис, т.к. благодаря ему
мы будем управлять узлами.
Далее заберем ядро (2.4.26) с включенными патчами
для OpenMosix (32 Мб):
wget http://citkit.dl.sourceforge.net/sourceforge/openmosix/openmosix-kernel-source-2.4.26-openmosix1.i386.rpm
Для экономии трафика можно взять только патчи и
наложить их на оригинальное ядро с kernel.org самостоятельно (200 Кб):
wget
http://citkit.dl.sourceforge.net/sourceforge/openmosix/openMosix-2.4.26-1.bz2
# rpm -ih --nodeps
openmosix-kernel-source-2.4.26-openmosix1.i386.rpm
# cd /usr/src/linux-2.4.26-openmosix1/
# make xconfig
Ставим галочки для компонентов OpenMosix (рис.
1), остальные компоненты для ядра не изменяем, сохраняем конфигурацию и
собираем ядро.
# makedep&& make
&& make bzImage && make modules
# make modules_install
Добавляем нужную опцию в загрузчик. В случае lilo:
image = /boot/mosix-bzImage
root = /dev/sda1
label = om.Linux
read-only
# /sbin/lilo -v
И перезагрузка.

Рисунок 1. Компоненты ядра,
отвечающие за функционирование OpenMosix
Для управления и тюнинга узлов в OpenMosix
предусмотрен специальный пакет утилит – openmosix-tools. Установим его.
wget
http://citkit.dl.sourceforge.net/sourceforge/openmosix/openmosix-tools-0.3.6-2.tar.gz
# tar xzvf
openmosix-tools-0.3.6-2.tar.gz
# cd openmosix-tools-0.3.6-2
# ./configure --prefix=/opt/OpenMosix
--with-kerneldir=/usr/src/linux-2.4.26-openmosix1
# make && make install
После установки этого пакета есть два варианта, каким
именно образом узлы будут сообщать друг другу о своих характеристиках
(загрузка, вычислительная мощность) и координатах (IP-адрес). Либо указать
жестко в файле /etc/openmosix.map, либо положиться на сервис автоопределения
узлов (omdiscd). Структура файла openmosix.map представлена ниже:
# MOSIX-# IP number-of-nodes
#
============================
1 10.0.0.1 1
100 0.0.0.100 1
В первой колонке указывается номер узла (в моем
случае первый узел имеет номер 1, второй – 100), во второй колонке IP-адрес, в третьей
колонке – количество узлов в диапазоне. Т.е. предполагая, что первые пять узлов
имеют последовательные адреса от 10.0.0.1 до 10.0.0.5 смысла их перечислять
нет. Стоит только указать, что количество узлов равно в этом случае 5.
1 10.0.0.1 5
Так раздаются адреса статически.
А для их динамического определения будет использоваться файл /etc/openmosix/openmosix.config,
где прописываются такие параметры, как:
n AUTODISCIF – имя интерфейса, через который
производит автопоиск (если на узле несколько сетевых интерфейсов).
n MYOMID – номер данного узла.
n MIGRATE – разрешать ли процессам миграцию с
данного узла или нет.
n MFS – использовать Mosix FileSystem или нет.
Я пошел по пути динамического определения узлов и
для этого включил старт автоматического определения omdiscd – добавил в /etc/rc.d/rc.local
строку:
/opt/OpenMosix/sbin/omdiscd -i
eth0
Таким образом, при последовательном старте узлов
вы можете отслеживать в логах процесс формирования кластера:
Jul 26 22:01:57
athlon kernel: openMosix #1 is at IP address 10.0.0.1
Jul 26 22:01:57
athlon omdiscd[1996]: Notified kernel to activate openMosix
Jul 26 22:02:55
athlon kernel: eth0: Setting full-duplex based on MII #1 link partner capability
of 45e1.
Jul 26 22:04:11
athlon kernel: openMosix configuration changed: This is openMosix #1 (of 2 configured)
Jul 26 22:04:11
athlon kernel: openMosix #1 is at IP address 10.0.0.1
Jul 26 22:04:11
athlon kernel: openMosix #100 is at IP address 10.0.0.100
Для того чтобы системные процессы (те, что
отвечают за загрузку и выключение узла) не мигрировали на другие узлы,
используем в файле /etc/inittab такую конструкцию: строки с участием директории
rc.d:
si:S:sysinit:/etc/rc.d/rc.S
перепишем так:
si:S:sysinit:/bin/mosrun -h /etc/rc.d/rc.S
что дословно означает «запускать стартовый скрипт rc.S на домашнем узле».
Также следует поменять строки, где участвует rc.d,
а также строку:
ca::ctrlaltdel:/sbin/shutdown
-t5 -r now
которая будет выглядеть так:
ca::ctrlaltdel:/bin/mosrun -h
/sbin/shutdown -t5 -r now
Все готово, чтобы первый настроенный узел
клонировать на другие машины. Воспользуйтесь либо командой dd, либо программой Norton
Ghost. Затем в клонированных узлах поменять IP-адреса, hostname, и дело в
шляпе.
Для тестирования производительности
сформированного кластера я решил проверить, за какое время будет собран MPlayer
[2].
Тестируем быстродействие
Как я проводил замеры. Когда кластер обнаруживает новый узел, он создает в
виртуальном каталоге /proc/hpc/nodes новую ветку, совпадающую с номером
обнаруженного узла. Следует отметить, что весь каталог /proc/hpc относится к
функционированию OpenMosix. Таким образом, если появляется новый узел с номером
XXX, то автоматически появляется каталог /proc/hpc/nodes/XXX, в котором
хранятся файлы с характеристиками данного узла. В частности, содержимое файла load
нас и будет интересовать. Производительность узлов в OpenMosix оценивается по
сравнению с виртуальной ПЭВМ класса Celeron 1 ГГц, поэтому не удивляйтесь,
когда увидите, что производительность конкретного узла, например, равняется
20000. Это означает, что по сравнению с эталонным 1 ГГц данный узел в 2 раза
производительнее.
Итак, производим калькуляцию. Сохраним данный скрипт,
использующийся в наших подсчетах в дальнейшем.
#!/bin/sh
NODE1=/proc/hpc/nodes/573
NODE2=/proc/hpc/nodes/574
NODE3=/proc/hpc/nodes/575
FILENAME=hpc_load.txt
i=0
while true
do
DateStr='date +%H-%M-%S'
Load1='cat $NODE1/load'
Load2='cat $NODE2/load'
Load3='cat $NODE3/load'
echo "$DateStr ($i):
$Load1, $Load2, $Load3" >> $FILENAME
echo "Time: $DateStr
($i). Load: $Load1, $Load2, $Load3";
i='expr $i + 1';
sleep 1s;
done
Скрипт получился простеньким для понимания.
Нагрузку «в попугаях» мы трансформируем в график, где посмотрим, какое участие
принял каждый конкретный узел в процессе сборки.
Так как считается, что кластер в нашем случае –
это единое пространство с увеличенным количеством процессоров, то используем
данный факт. Сначала посчитаем время сборки, когда работает только один узел,
самый быстрый. Предварительно распакуем MPlayer:
# wget MPlayer
# tar xzvf MPlayer
# cd MPlayer
# ./configure
Теперь запускаем наш скрипт collect_hpc_load.sh и
считаем время:
# time make dep
# time make
real
0m19.068s
user
0m2.570s
sys
0m16.410s
real
5m11.963s
user
3m44.950s
sys
1m26.410s
Включаем узел с самым медленным CPU. Теперь
производим подсчет.
real
0m20.693s
user
0m2.670s
sys
0m17.450s
real
5m17.013s
user
4m5.820s
sys
1m43.620s
Получили еще худший результат. Почему? Очень
просто – у нас сформировалось много процессов, но с маленькими вычислительными
запросами. Общее время миграции по 100-Мбитной сети плюс время компиляции
превысило предыдущий результат.
Включаем третий узел с 1.8 ГГц CPU. Посмотрим на
цифры.
real
0m24.860s
user
0m2.800s
sys
0m17.610s
real
4m18.754s
user
4m17.620s
sys
2m16.540s
Отлично. А что произойдет при отключении самого
медленного узла? Отключаем, проверяем.
real
0m23.539s
user
0m3.260s
sys
0m17.580s
real
4m24.304s
user
4m18.270s
sys
2m14.320s
Выигрыш от медленного узла составил примерно 6
секунд. Как говорится – спорный результат. Стоит ли овчинка выделки – а именно,
нужен ли третий узел? Очевидно стоит отказаться в пользу двухузловой модели.
Полученные результаты удобнее анализировать
графически. Импорт в OpenOffice и дальнейшее преобразование в диаграммы
закончилось получением этих рисунков. Синим цветом отмечен узел на базе Pentium
4 CPU 3 ГГц, красным – узел Pentium 4 CPU 1.8 ГГц, белым – Pentuim 3 CPU
600 МГц (рис. 2-5).

Рисунок 2. Загрузка кластера
при одноузловом варианте

Рисунок 3. Загрузка кластера
при двухузловом варианте (оба узла Pentium 4)

Рисунок 4. Загрузка кластера
при двухузловом варианте (один из узлов Pentium 3)

Рисунок 5. Загрузка кластера
при трехузловом варианте
Утилиты мониторинга
Как производить текущий мониторинг загрузки? К счастью, у OpenMosix достаточно
широкая аудитория пользователей, благодаря которым появились утилиты
визуального контроля и управления. Нужный нам сейчас пакет называется openmosixview.
# wget
openmosixview-1.5.tar.gz
# tar xzvf
openmosixview-1.5.tar.gz
# cd openmosixview-1.5
Данное ПО написано на QT –
надеюсь, вы его поставили, не забыли. Оно состоит из следующих программ:
n openMosixview – приложение для мониторинга и
управления кластера.
n openMosixprocs – приложение, показывающее
процессы и их свойства.
n openMosixcollector – сервис по сбору
статистики.
n openMosixanalyzer – приложение для анализа
данных, собранных сервисом статистики.
n openMosixhistory – приложение, для просмотра
миграций процессов в определенный момент времени.
n openMosixpidlog – приложение для мониторинга единичных
процессов.
n 3dmosmon – приложение для объемного мониторинга
кластера.
К сожалению, у меня последняя программа не
захотела собираться. Решение оказалось простым – при компиляции приложения
3dmosmon следует заменить инициализацию переменных в файле materials.h из вида:
static material_struct whiteMaterials
= {
{1.0, 1.0, 1.0, 1.0},
{0.0, 0.0, 0.0, 1.0},
{1.0, 1.0, 1.0, 1.0},
{20.0}
};
в вид:
static material_struct whiteMaterials
= {
{1.0, 1.0, 1.0, 1.0},
{0.0, 0.0, 0.0, 1.0},
{1.0, 1.0, 1.0, 1.0},
20.0
};
А для приложения mosstatd добавить ключи, чтобы
строка выглядела следующим образом (красным шрифтом отмечены добавленные
параметры):
gcc -I/usr/src/linux-2.4.26-openmosix1/include/
-I/usr/local/openmosix-tools/include/ -o mosstatd -L/usr/local/openmosix-tools/lib/ -lmos mosstatd.c
В итоге, запустив предварительно сервис сбора
статистики mosstatd (например, через инициализационный скрипт /etc/rc.d/rc.local),
мы сможем отслеживать загрузку кластера в виде трехмерного изображения (см.
рис. 6).
# 3dmosmon localhost

Рисунок 6. Трехмерное
изображение загрузки кластера
Сборка остальных программ достаточно тривиальна:
# cd openmosixview
# make
# ./openmosixview
По такому же принципу собираются и остальные
утилиты.
openMosixview – наглядный пример, какие узлы в
данный момент загружены и общая картина по производительности (см. рис. 7).

Рисунок 7. Визуальная картина
загрузки посредством утилиты openMosixview
Приведена ситуация, когда отключен наименее производительный
узел. Отключение узла от кластера отображается индикатором красного цвета.
Графическая утилита openmosixmigmon позволяет,
не утруждая себя поисками PID конкретного процесса, перебросить его
выполнение на другой узел (см. рис. 8).

Рисунок 8. Контроль за
миграцией процессов в кластере
В частности, некоторые процессы с головного узла
уже насильно мигрированы к соседям и используют их вычислительные мощности.
Следующая интересная утилита из данного пакета
называется openMosixanalyzer. Видна нагрузка как в целом на кластер, так и на
отдельные узлы за определенный момент времени (см. рис. 9).

Рисунок 9. Статистика по
загрузке кластера в определенное время
А чтобы такая статистика велась на постоянной
основе, придуман сервис openMosixcollector, как видим из названия, его работа
заключается в сборе данных и сохранении их на диске.
Запускается он просто – «openmosixcollector -d» –
работает в качестве сервиса. Собранная информация раз в сутки сбрасывается в
директорию /tmp/openmosixcollector_ДАТА_ВРЕМЯ.
Давайте теперь ознакомимся с утилитами по
настройке кластера.
mosctl – утилита для просмотра/редактирования
параметров узла.
Рассмотрим характерные конструкции на основе
данной утилиты.
# mosctl --help
Usage: mosctl command
Available commands:
stay/nostay, lstay/nolstay, block/noblock, quiet/noquiet,
mfs/nomfs, expel, bring, gettune, getdecay,
whois [mosix_no|IP-address|hostname],
getload [node-number], getspeed [node-number],
status [node-number], getmem [node-number],
getfree [node-number], getutil [node-number],
getyard, setyard [node-type], setspeed speed,
setdecay interval(seconds) slow(/1000) fast(/1000),
isup
[node-number]
n mosctl whois node0
– выводит IP-адрес узла node0;
n mosctl getload node0 – выводит загрузку узла
node0;
n mosctl getspeed node0 – выводит скоростную
характеристику узла node0;
n mosctl gettune – выводит показатели для данного
узла;
n mosctl bring – передает сигнал мигрированным
процессам для возврата на домашний узел.
Как видите, тот пример, что мы рассмотрели и
использовали в своей работе, можно переписать намного нагляднее при
использовании утилиты mosctl.
# moslimit --help
Usage: moslimit
command
Available commands:
setloadlimit
[numeric-value], setcpulimit [numeric-value],
setllimitmode
[numeric-value], setcpulimitmode [numeric-value],
getloadlimit
[node-number], getcpulimit [node-number],
getllimitmode
[node-number], getcpulimitmode [node-number],
getloadlocal
[node-number], getcpulocal [node-number],
getloadremote
[node-number], getcpuremote [node-number]
Для миграции процессов в пределах кластера
предназначена утилита migrate.
# migrate --help
Usage: migrate pid
{OpenMosix-ID|home|balance}
А вот список процессов, который мы сможем увидеть
при запуске утилиты ompsinfo.
root@node0:~# ompsinfo
CMD
PID NODE NMIGS LOCK CANTMOVE
init
1 0 0 0 system
keventd
2 0 0 0 clone_vm
ksoftirqd_CPU0
3 0 0 0 clone_vm
kswapd
4 0 0 0 clone_vm
bdflush
5 0 0 0 clone_vm
kupdated
6 0 0 0 clone_vm
khubd
8 0 0 0 clone_vm
kjournald
10 0 0 0 clone_vm
oM_migd
11 0 0 0 system, clone_vm
oM_infoD
12 0 0 0 system, clone_vm, rt_sched
memsorter
13 0 0 0 system, clone_vm
syslogd
62 0 0 1 migratable but locked
klogd
65 0 0 1 migratable but locked
inetd
340 0 0 1 migratable but locked
sshd
343 0 0 0 migratable
crond
351 0 0 1 migratable but locked
gpm
360 0 0 1 migratable but locked
agetty
362 0 0 0 migratable
agetty
363 0 0 0 migratable
agetty
364 0 0 0 migratable
agetty
365 0 0 0 migratable
agetty
366 0 0 0 migratable
agetty
367 0 0 0 migratable
omdiscd
398 0 0 0 migratable
mosstatd
476 0 0 0 migratable
sshd
2778 0 0 0 migratable
bash
2780 0 0 0 migratable
ompsinfo
2852 0 0 0 migratable
Утилита mosmon предназначена для визуального
отображения текущей загрузки кластера. Она скомпилирована на основе библиотеки ncurses,
поэтому текстовой консоли вполне будет достаточно для ее запуска.
Для запуска заданий предназначена утилита mosrun.
С ее помощью можно указать, к какому типу процессов принадлежит наше задание. Либо
это CPU-intensive, т.е. задание, использующее процессорные ресурсы, либо I/O-intensive
– задание, где основной упор делается на процесс ввода/вывода.
Usage: mosrun
[-{h|OpenMosix_ID|-jID1-ID2[,ID3-ID4]...} [-F] ] -{l|L|k}
[-{c|i|n|s|f | ([-d dec] [-t tt])} [-{e|E}] [-{r|R}] ]
[-z] prog [args]..
Утилита showmap выводит список узлов кластера.
root@node0:~# showmap
My Node-Id:
0x023d
Base Node-Id Address
Count
------------
---------------- -----
0x023d
192.168.2.61 1
0x023f
192.168.2.63 1
Сервис, отвечающий за динамическое определение
узлов кластера. В частности, когда на узле используется несколько сетевых
интерфейсов, следует явно указать, по какому из них проводить идентификацию
узлов.
omdiscd-i eth0
Выводы
Как и в любом аспекте нашей жизни можно найти минусы и плюсы, так и решения
на базе OpenMosix-кластера содержат некие «узкие» точки. В частности, оцифровка
звуковых файлов из формата .wav в формат .mp3 показала, что общее время
процесса обработки на кластере превысило аналогичное время на одной ПЭВМ.
Повлияла на столь странный результат низкоскоростная среда передачи данных –
100-мегабитная сеть. В целом применение OpenMosix-кластеров целесообразно в тех
случаях, когда требуется использовать задачи с высокими интенсивными
вычислительными запросами, например сборка программного обеспечения (как
показано в этой статье), симуляторы погоды, обработка геофизических данных,
математических моделей и в других подобных ситуациях.
Ссылки,
литература:
1. Борисов
А. «Стальной глаз на страже жизни». HA-кластер LifeKeeper компании SteelEye. –
Журнал «Системный администратор», №7, 2004 г. – 43-49 с.
2. http://www.mplayerhq.hu.
3. http://openmosix.sourceforge.net.
4. http://www-128.ibm.com/developerworks/eserver/articles/openmosix.html.
5. http://howto.x-tend.be/openMosixWiki.
6. http://howto.x-tend.be/openMosix-LCA2005.
7. http://tab.snarc.org/article/om_internals.xhtml.
8. http://www.samag.com/documents/s=9658/sam0505a/0505a.html.