Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Современные технологии разработки распределенных вычислительных систем. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
15.08.2026
Размер:
1 Мб
Скачать

по запросу от узла-исполнителя (стратегия pull), либо по инициативе мастер-

узла (стратегия push).

В первом случае поток pull-запросов постоянно приносит мастер-узлу информацию об активности тех или иных исполнителей в каждый момент времени и готовности их к выполнению заданий, поэтому никакого дополнительного списка участников вычислений мастеру не требуется. При такой организации распределенная система включает в себя неопределенное множество логических процессоров и, как следствие, эффективно масштабируется. Однако не для всех прикладных алгоритмов pull-стратегия является применимой: неопределенность количества исполнителей на каждой фазе алгоритма может означать как нехватку, так и избыток вычислительных мощностей, без возможности управления этими ресурсами.

Таким образом, система с неопределенным реестром исполнителей

подходит для прикладных алгоритмов, допускающих последовательно-

параллельную обработку элементов данных при нехватке вычислительных ресурсов.

При отсутствии инициативы от исполнителей мастер-узел должен обладать возможностью “проталкивать” (push) задания конкретным логическим процессорам, для чего требуется ведение соответствующего реестра.

Регистрация исполнителей может быть единовременным этапом

(фиксированный реестр), а может выполняться постоянно на протяжении всего времени работы прикладного алгоритма (динамический реестр). Общим недостатком ведения реестра исполнителей являются накладные расходы,

затрачиваемые на обмен сообщениями при регистрации узлов.

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

11

является пониженная надежность при неконтролируемом отключении узлов-

исполнителей после регистрации.

Таким образом, применение фиксированного реестра исполнителей подходит для распределенных систем, ориентирующихся на относительно стабильное состояние подключенных вычислительных узлов.

Самым сложным вариантом в рассматриваемом аспекте является применение динамического реестра исполнителей. Мастер-узел в любой момент может принять от узла-исполнителя заявку на участие в распределенных вычислениях, либо отказ от участия. Состав множества логических процессоров, задействованных в системе, способен меняться, но в каждый момент времени он является вполне определенным – в соответствии с фиксацией узлов в динамическом реестре. Само по себе применение динамического реестра узлов не гарантирует надежности системы, однако алгоритмы распределения заданий между исполнителями изначально проектируются с возможностью адаптации к меняющемуся количеству участников вычислительного процесса, причем, с большей эффективностью,

чем в системах с неопределенным реестром.

2.2. Способы активации прикладного кода

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

12

Фактически, рассматриваемый аспект относится к выбору способа запуска прикладных процедур. Прикладная процедура запускается либо в процессе реакции на входящее сообщение, адресованное конкретному логическому процессору (система должна идентифицировать процессоры), либо в процессе реакции на какое-либо событие, происходящее в распределенной среде

(система должна идентифицировать события).

Достоинства первой схемы (message-oriented, MO) – прозрачность структуры, локально-временная предсказуемость обработки данных,

упрощение стека системного ПО, возможность локального кэширования данных прикладными процедурами. Этот подход является более низкоуровневым и, как следствие, более гибким, более универсальным,

вносящим меньшие накладные расходы.

Основным достоинством второй схемы (event-oriented, EO) является упрощение прикладной логики при исключительной эффективности масштабирования. Однако со стороны системной инфраструктуры требуется специальная поддержка связывания событий с обработчиками. Программный код обработчиков событий принципиально не связан с конкретными компьютерами, поэтому исполнение прикладных процедур может мигрировать между различными узлами вычислительной сети, в зависимости от степени загруженности и доступности локальных ресурсов.

Выбор типа узлов распределенной системы существенно влияет на проектирование прикладных алгоритмов. Вариант MO представляется более подходящим для использования парадигмы MPI (Message Passing Interface),

поскольку основные операции MPI (send, receive, broadcast, reduce и др.)

являются естественными для среды с распределенной памятью,

функционирующей на основе обмена сообщениями между адресуемыми логическими процессорами. Однако следует принимать во внимание, что не всегда узлы распределенной системы обладают возможностью прямых коммуникаций (peer-to-peer). Часто используется звездообразная топология,

13

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

ориентируются на фиксированное количество логических процессоров в группе параллельной обработки данных.

Вариант EO позволяет эффективно использовать в распределенной среде алгоритмические решения, основанные на поведенческом паттерне “Издатели – Подписчики” (Publishers – Subscribers). В этом случае требуется составить реестр всевозможных событий, которые могут возникать в распределенной системе, и определить алгоритмы реакции на каждое из этих событий. В свою очередь, алгоритм реакции может порождать новые события.

Функционирование системы начинается с порождения стартового события.

2.3. Развертывание прикладного программного обеспечения распределенных систем

Важным аспектом распределенных систем является схема доставки прикладного программного кода на вычислительные узлы. В соответствии с распространенной современной концепцией “Software-as-a-Service” (SaaS)

программное обеспечение должно быть доступно в любое время из любой точки, с любого устройства, подключенного к глобальной сети Internet [5].

Таким образом, любая веб-система является глобально распределенной.

Клиенты веб-систем – это либо браузерные сеансы (WebClient), либо мобильные приложения (MobileClient), либо, значительно реже, десктопные программы (DesktopClient).

Доставка прикладного кода для клиентов типа WebClient является самой простой – загрузка программ (сценариев на языке JavaScript) осуществляется вместе с загрузкой веб-страниц. Мобильные приложения, как правило,

14

требуется устанавливать по инициативе пользователя из специализированных магазинов приложений, а установка десктопных программ часто требует прав администратора. Таким образом, с точки зрения удобства развертывания прикладного ПО вычислительных узлов внутрибраузерные JavaScript-сценарии являются одним из наиболее эффективных решений.

Расширение функциональных возможностей современных браузерных API

и технологий (Web Sockets, Worker) позволяет использовать в JavaScript-

контексте дуплексный обмен данными, получать push-оповещения с серверной стороны, проводить параллельные вычисления на многоядерных центральных процессорах. Браузерные сценарии имеют существенные ограничения доступа к файловой системе (требуется интерактивный контроль чтения и записи файлов). Кроме того, для них в настоящее время недоступны API

высокопроизводительных вычислений с массовым параллелизмом (OpenCL,

CUDA).

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

2.4. Распределенные системы с активными сообщениями

Распределенную вычислительную систему принято рассматривать как совокупность узлов, на которых выполняются программы – обработчики сообщений. Как правило, сообщения переносят между узлами данные или управляющие команды, но не программный код (за исключением фазы

15

развертывания системы); используется метафора: “умные узлы” (intelligent nodes) передают и обрабатывают “пассивные сообщения” (dumb messages).

Возможна и обратная схема, для которой, по сложившейся традиции,

используется термин “активные сообщения” (active messages), поскольку такие сообщения внутри себя содержат программу, определяющую необходимое поведение при загрузке на исполнительный узел. Исполнитель после приема активного сообщения должен запустить имеющуюся в нем программу с аргументом – блоком данных из этого же сообщения. Таким образом,

программа и данные сопровождают друг друга, образуя особую (ультраслабую)

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

(идентификатором), по которому можно извлечь код программы из какого-либо источника.

Более точной характеристикой, позволяющей различать уровни сцепления,

является степень присутствия прикладного кода для обработки сообщений типа

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

Y. При слабом сцеплении код обработки X должен быть внедрен после запуска исполнительного узла, но до начала приема сообщений этого типа; при необходимости, прикладной код можно изменить с X на Y без перезапуска,

после чего система утратит способность принимать и обрабатывать X.

При ультраслабом (сопровождающем) сцеплении код обработки X может отсутствовать на узле-исполнителе до момента приема сообщения этого типа.

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

16

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

Недостатки распределенных систем с активными сообщениями:

1) повышенные накладные расходы на запуск обработки блоков данных

(компиляция, сборка, создание процессов и потоков, другие формы подготовки программы к исполнению);

2)дополнительный объем трафика на пересылаемый прикладной код;

3)необходимость усиленных мер по обеспечению информационной безопасности (система предоставляет исполнительную среду для любых видов

“активности”, в том числе, потенциально вредоносной).

3. Распределенные вычислительные системы на платформе NodeJS

3.1. Общие сведения о платформе NodeJS

NodeJS – свободно распространяемая кроссплатформенная среда исполнения программ на языке JavaScript [1]. Она построена на основе открытого программного компонента Google Chrome V8, осуществляющего трансляцию JavaScript в машинный код и управляющего его исполнением.

Как известно, язык JavaScript получил широкое распространение благодаря эволюции веб-браузеров, в которых он используется для поддержки интерактивных веб-страниц. Браузерный контекст исполнения программ

(скриптов) на JavaScript накладывает существенные ограничения на функциональность реализуемых алгоритмов. Причина этих ограничений – требования безопасности веб-страниц. Сам по себе JavaScript является полноценным универсальным языком программирования, для которого можно организовать эффективную высокопроизводительную среду исполнения,

обеспечивающую доступ к файловой системе, сетевым коммуникациям,

17

позволяющую запускать и контролировать дочерние процессы. Именно такой средой является NodeJS.

После установки NodeJS появляется возможность осуществлять запуск

JavaScript-программы из командной строки:

$>node test.js foo bar

В данном примере исходный текст на JavaScript находится в файле test.js,

программа получает аргументы “foo” и “bar”. (Точнее, “test.js”, “foo” и “bar”

являются аргументами программы node, ядра NodeJS.)

Современная IT-индустрия по достоинству оценила удобство и эффективность NodeJS. На этой платформе создаются надежные,

масштабируемые серверные системы с высокой пропускной способностью. В

то же время, NodeJS может найти широкое применение и в академической среде для построения разнообразных экспериментальных программных систем на языке JavaScript.

3.2. Установка NodeJS и NPM

Обычно для исполнения программ на JavaScript используется веб-браузер,

поэтому на компьютер пользователя не требуется устанавливать дополнительное ПО, но для работы с NodeJS необходимо провести стандартную процедуру установки исполняемых файлов. Ссылки на скачивание дистрибутива под конкретную ОС (автоматически настроенные в соответствии с информацией, полученной от браузера) доступны на главной странице проекта (nodejs.org). На странице загрузок (nodejs.org/en/download/) размещены ссылки на дистрибутивы под все ОС, поддерживаемые проектом.

18

Стандартные дистрибутивы помимо установки среды исполнения node

предусматривают также установку менеджера пакетов npm. Менеджер пакетов npm позволяет загружать модули на JavaScript из обширного централизованного репозитория, чем обеспечивается повторное использование программного кода.

$>npm install redis

В этом примере с помощью npm командой install производится установка модуля redis (клиент сервиса Redis, он потребуется для разработки распределенной вычислительной системы).

3.3. Использование NodeJS Cluster для организации параллельных вычислений

NodeJS исполняет JavaScript-код в однопоточном контексте, но использует асинхронную модель выполнения операций ввода/вывода. В асинхронных алгоритмах потенциально продолжительные действия явно разделяются на две фазы: 1) старт операции и 2) получение и анализ результатов, завершение операции. Таким образом, непосредственно ввод/вывод может выполняться после старта в фоновом режиме сколь угодно долго – клиентский поток в это время свободен для других действий. С точки зрения прикладного программиста асинхронная операция после старта выполняется параллельно с

основным потоком.

Однако в базовом однопоточном контексте NodeJS невозможно в явном виде задействовать вычислительные ресурсы многоядерных CPU. Поэтому

NodeJS предоставляет средства запуска дочерних процессов, работающих параллельно с основным процессом node. Реализует эту парадигму модуль

Cluster, с помощью которого удобно запускать несколько дочерних процессов.

19

Рассмотрим вычислительную задачу получения оценки числа π методом Монте-Карло. Производится генерация N пар псевдослучайных чисел {xi, yi}, xi, yi [0 .. 1], геометрически соответствующих случайно выбранным точкам внутри единичного квадрата 0 ≤ x ≤ 1, 0 ≤ y ≤ 1. Пусть C – количество пар, в

которых x2 + y2 ≤ 1 (точки, попавшие на сектор единичного круга). Тогда

π / 4 ≈ C / N. Для повышения точности оценки следует генерировать как можно больше тестовых пар (N ∞). Вероятность повторения пар при использовании качественного псевдослучайного генератора низка, ей можно пренебречь.

Этот алгоритм, возможно, является одним из самых неэффективных для нахождения числа π, зато он идеально подходит для иллюстрации параллельной вычислительной схемы.

Ниже приведен код функции calcMonteCarloPi, которую будут вызывать дочерние процессы (этот код будет опущен во всех последующих программах):

function calcMonteCarloPi(pointsCount)

{

var inCircleCount = 0;

for (var i = 0; i < pointsCount; ++i)

{

const x = Math.random(); const y = Math.random(); if(x * x + y * y < 1)

{

++inCircleCount;

}

}

return 4 * inCircleCount / pointsCount;

}

После возврата из этой функции дочерний процесс должен передать вычисленную оценку числа π родительскому процессу.

20

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]