arma-thesis

git clone https://git.igankevich.com/arma-thesis.git
Log | Files | Refs | LICENSE

commit 3dceb6e4d3fdd4db295cc0fec135ab37bcd2ba05
parent 3f2425046b81ccb56f492b4832682ce3283f1508
Author: Ivan Gankevich <igankevich@ya.ru>
Date:   Mon, 23 Jan 2017 10:34:34 +0300

Copy tbe rest of the Russian text from final work.

Diffstat:
phd-diss-ru.org | 526+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 526 insertions(+), 0 deletions(-)

diff --git a/phd-diss-ru.org b/phd-diss-ru.org @@ -2289,10 +2289,536 @@ arma.plot_factory_vs_openmp_overlap( ** Реализация для систем с распределенной памятью (MPP) *** Обзор архитектур распределенных систем +Многие распределенные системы построены по принципу /субординации/: в каждом +кластере выбирается главный узел, который управляет очередью задач решаемых на +кластере и мониторингом их выполнения. Роль главного узла может задаваться как +/статически/, путем выделения конкретного физического узла под нее, так и +/динамически/, путем избрания какого-либо из узлов кластера главным. В первом +случае отказоустойчивость обеспечивается посредством резервирования +дополнительного свободного узла, который займет место главного в случае отказа +оборудования. Во втором случае отказоустойчивость обеспечивается выбором нового +главного узла из оставшихся в случае отказа текущего. Несмотря на то что +динамический распределение ролей требует наличия распределенного алгоритма, этот +подход становится все более и более популярным, поскольку не требует наличия +простаивающих резервных узлов на случай отказа главного узла. + +Алгоритмы выбора лидера (которые иногда называют алгоритмами распределенного +консенсуса) являются частными случаями волновых алгоритмов. В +cite:tel2000introduction Тель определяет их как алгоритмы, в которых событие +завершения программы предваряется хотя бы одним каким-либо другим событием, +происходящем в /каждом/ параллельном процессе. Волновые алгоритмы не определены +для анонимных сетей, т.е. они работают только с теми параллельными процессами, +которые могут себя уникально идентифицировать. Однако, количество процессов, +которых затрагивает "волна" может быть определено по мере выполнения алгоритма. +В рамках распределенных систем это означает, что волновые алгоритмы подходят для +вычислительных кластеров с динамически меняющимся количеством узлов, так что +включение и выключение отдельных узлов не влияет на работу алгоритма. + *** Алгоритм обнаружения узлов кластера +**** Введение. +Подход к динамическому выбору главного узла, исследованный в данной работе, не +использует волновые алгоритмы, а значит не требует опроса кворума узлов для +выбора лидера. Вместо этого каждый узел кластера составляет список других узлов +подсети, в которой он находится, и простым алгоритмом преобразует список в +/древовидную иерархию/ с заданным значением ветвления (максимальным +количеством подчиненных вершин). Затем узел определяет уровень иерархии, на +котором он находится и пытается соединиться с вышестоящими узлами, чтобы стать +их подчиненным. Сначала он проверяет близко расположенные к нему узлы, а потом +все остальные узлы вплоть до вершины иерархии. Если вышестоящих узлов нет или с +ними невозможно соединиться, то этот узел становится главным. + +Древовидная иерархия узлов подсети определяет отношение строгого порядка на +множестве всех узлов кластера. С технической точки зрения любая функция может +быть выбрана для присвоения узлу подсети номера в списке, однако, на практике +эта функция должна быть достаточно гладкой вдоль временной оси и иметь лишь +редкие скачки: быстрые изменения в структуре иерархии узлов могут привести +постоянной передачи роли главного узла от одного узла к другому, что сделает +кластер неуправляемым. Простейшей такой функцией является позиция IP-адреса +узла в диапазоне всех IP-адресов подсети. + +Основной особенностью алгоритма является многоуровневая субординация, т.е. +выбор сразу нескольких лидеров в рамках одной подсети в зависимости от значения +ветвления иерархии. Это позволяет делать локальные изменения в структуре +иерархии, не затрагивающие всех узлов кластера, и определить адрес +потенциального главного узла еще до начала алгоритма. Подход отличается от +волновых алгоритмов наличием сразу нескольких лидеров в одной подсети, +использованием IP-адресов узлов в качестве уникального идентификатора и +критерия ранжирования, а также отсутствием какой-либо предварительной +коммуникации между узлами, которая нужна для определения их ранга. + +Алгоритм /субординации/, исследованный в данной работе, позволяет объединить +узлы вычислительного кластера в распределенную систему без какой-либо +предварительной конфигурации, только лишь установив и запустив соответствующие +сервисы на каждом из узлов. При выходе из строя одного из узлов эти сервисы +способны самостоятельно найти исправный узел и стать его подчиненным, или же +занять вершину иерархии. Такая автономность работы выгодно отличает субординацию +от традиционных подходов к управлению вычислительным кластером, который включает +в себя ручную настройку главного и подчиненных узлов, а также резервного узла +для обеспечения отказоустойчивости. + +В отличие от других алгоритмов выбора лидера +cite:brunekreef1996design,aguilera2001stable,romano2014design, алгоритм +субординации не предназначен для управления одновременным обновлением записей в +распределенной базе данных несколькими параллельными процессами; вместо этого +основной областью применения алгоритма служит распределение нагрузки на большое +количество узлов кластера. Обычно, кластер управляет одним главным узлов (или +1-2 узлами для обеспечения отказоустойчивости), который собирает данные +мониторинга, ведет учет потребленных пользователями ресурсов, позволяет изменять +настройки всего кластера и ставит задачи в очередь для запуска. Для больших +кластеров одного главного узла может быть недостаточно, чтобы справиться с +нагрузкой, и в этом случае введение подчиненных узлов, управляющих отдельными +частями кластера, может решить эту проблему. + +Алгоритм субординации предполагает, что IP-адрес узла изменяется редко (при +этом один и тот же IP-адрес необязательно должен быть закреплен за определенным +узлом). Практика показывает, что это предположение выполняется для кластеров, +однако это может стать проблемой для виртуальных кластеров, создаваемых на +ресурсах облачных провайдеров: в таких кластерах IP-адрес может меняться +произвольно с сохранением DNS-имени узла. Использование алгоритм субординации в +такой среде может привести к постоянному переназначению ролей узлов кластера, +что не позволит эффективно распределять нагрузку. + +Суммируя вышесказанное, алгоритм субординации не подходит для сред, в которых +IP-адреса меняются часто, основной сферой применения алгоритма является +распределение нагрузки на вычислительный кластер и алгоритм не требует +какой-либо предварительной конфигурации. +**** Построение древовидной иерархии. +Субординация на множестве $\mathcal{N}$ узлов одной подсети определяется как +\begin{equation*} +\forall n_1 \forall n_2 \in \mathcal{N}, +\forall f \colon \mathcal{N} \rightarrow \mathcal{R}^n +\Rightarrow (f(n_1) < f(n_2) \Leftrightarrow \neg (f(n_1) \geq f(n_2))), +\end{equation*} +где $f$ --- отображение узла на его идентификационный номер, и $<$ --- оператор, +определяющий отношение строго порядка на множестве $\mathcal{R}^n$. Функция $f$ +присваивает узлу его порядковый номер, а оператор $<$ делает этот номер +уникальным. + +Простейшее отображение $f$ ставит в соответствие каждому узлу подсети позицию +его IP-адреса в диапазоне всех адресов подсети. Без преобразования к древовидной +структуре (когда в подсети выбирается только один лидер) рабочий узел, адрес +которого занимает наименьшую позицию в диапазоне, становится главным. Если адрес +узла занимает первую позицию в диапазоне, то для него невозможно выбрать лидера, +и он будет находится на вершине иерархии вплоть до выхода из строя. Несмотря на +то что идентификацию узлов на основе их IP-адресов легко реализовать в +программе, такой подход устанавливает искусственную зависимость роли главного +узла от IP-адреса. Тем не менее, этот подход полезен для первичного объединения +узлов в кластер, когда более сложные методы идентификации узлов неприменимы. + +Для того чтобы алгоритм субординации масштабировался на большое количество +узлов, структуру диапазона адресов подсети необходимо сделать древовидной. В +древовидной иерархии каждый узел идентифицируется уровнем $l$ иерархии, на +котором он находится и отступом $o$, который равен порядковому номеру узла на +его уровне. Значения уровня и отступа определяются из следующей задачи +оптимизации. +\begin{equation*} + n = \sum\limits_{i=0}^{l(n)} p^i + o(n), \quad + l \rightarrow \min, \quad + o \rightarrow \min, \quad + l \geq 0, \quad + o \geq 0 +\end{equation*} +где $n$ --- позиция IP-адреса узла в диапазоне IP-адресов подсети и $p$ --- +значение ветвления (максимальное количество подчиненных, которых может иметь +узел). Лидер узла на уровне $l$ с отступом $o$ будет иметь уровень $l-1$ и +отступ $\lfloor{o/p}\rfloor$. Расстояние между любыми двумя узлами в иерархии, +адреса которых занимают позиции $i$ и $j$ в диапазоне определяется как +\begin{align*} + & \langle + \text{lsub}(l(j), l(i)), \quad + \left| o(j) - o(i)/p \right| + \rangle,\\ + & \text{lsub}(l_1, l_2) = + \begin{cases} + \infty & \quad \text{if } l_1 \geq l_2, \\ + l_1 - l_2 & \quad \text{if } l_1 < l_2. + \end{cases} +\end{align*} +Расстояние имеет составную запись, чтобы при определении близости двух узлов +уровень иерархии учитывался в первую очередь. + +Для выбора лидера каждый узел ранжирует все узлы подсети в соответствии с +$\langle{l(n),o(n)}\rangle$ и, используя формулу для определения расстояния, +выбирает ближайший к потенциальному лидеру узел, имеющий наименьший ранг. Это +позволяет пропустить IP-адреса выключенных и просто несуществующих узлов, но для +разреженных сетей, в которых некоторые IP-адреса из середины списка не +закреплены за работающими узлами, сбалансированность дерева не гарантируется. + +Поскольку узлу для выбора лидера нужно соединиться только с узлом, адрес +которого известен заранее, то алгоритм субординации хорошо масштабируется на +большое количество узлов. Соединение с другими узлами из ранжированного списка +происходит только в том случае, если соединение с узлом из начала списка +прерывается. Таким образом, если адреса рабочих узлов расположены плотно в +диапазоне адресов подсети, каждый узел устанавливает соединение только со своим +узлом-лидером, и ресурсоемкого и неэффективного сканирования всей сети каждым +узлом не происходит. + +**** Результаты тестирования. +Платформа, на которой осуществлялось тестирование, состоит из одного +многопроцессорного узла, на котором развертывается виртуальный кластер из +заданного количества узлов с помощью пространств имен Linux. Похожий подход +используется в +cite:lantz2010network,handigol2012reproducible,heller2013reproducible, где +обосновывается целесообразность его применения для проведения экспериментов на +виртуальных кластерах и сопоставляются результаты некоторых из них с реальными +кластерами. Преимуществом данного подхода является низкие требования к +оборудованию, на котором проводятся эксперименты, а также отсутствие влияния +внешних процессов, выполняющихся параллельно с экспериментами. + +Тестирование производительности заключалось в построении графика зависимости +времени, затрачиваемого на объединение узлов в кластер, от количества узлов. В +процессе эксперимента любое изменение иерархии записывалось в файл и по +прошествии 30 сек. все процессы вынужденно останавливались системой. Пробные +запуски показали, что одновременный запуск более 100 виртуальных узлов искажал +результаты, поэтому для этого эксперимента были использованы дополнительные +физические узлы, на каждом из которых создавалось по 100 виртуальных. +Эксперимент показал, что объединение от 100 до 400 узлов в кластер занимает в +среднем 1,5 секунды (см. [[fig:bootstrap-local]]). Для полностью физического +кластера это значение может увеличиться. Пример древовидной иерархии, полученной +при запуске на 11 узлах представлен на [[fig:tree-hierarchy-11]]. + +#+name: fig:bootstrap-local +#+begin_src R +# TODO +#+end_src + +#+caption: Зависимость времени объединения узлов в кластер в зависимости от их количества. +#+RESULTS: fig:bootstrap-local + +#+name: fig:tree-hierarchy-11 +#+begin_src R +# TODO +#+end_src + +#+caption: Древовидная иерархия для 11 узлов. +#+RESULTS: fig:tree-hierarchy-11 + *** Алгоритм восстановления после сбоев **** Обеспечение отказоустойчивости. +Отказы узлов распределенной системы можно разделить на три типа: отказ +подчиненного узла, отказ главного узла и отказ одновременно всех узлов +(отключение электричества). Для того чтобы запущенная на кластере задача могла +продолжиться после отказа подчиненного узла, для нее периодически создаются и +записываются в надежное хранилище контрольные точки восстановления. При +создании контрольной точки все параллельные процессы задачи временно +останавливаются, образ памяти, выделенной операционной системой для процессов +задачи копируется на диск, и выполнение задачи продолжается в нормальном +режиме. Для того чтобы отказ главного узла не повлиял на работу кластера, +состояние сервисов, запущенных на нем, непрерывно копируется на резервный узел, +который становится главным при отказе. При незапланированном отключении +электричества состояние всех запущенных на момент отказа задач +восстанавливается из контрольных точек восстановления. + +Оптимизации работы контрольных точек восстановления посвящено большое +количество работ cite:egwutuoha2013survey, а альтернативным подходам +уделяется меньше внимания. Обычно высокопроизводительные приложения используют +передачу сообщений для обмена данными между параллельными процессами и хранят +свое текущее состояние в глобальной памяти, поэтому не существует способа +перезапустить завершившийся процесс, не записав образ всей выделенной для него +памяти на диск. Обычно общее число процессов фиксировано и задается +планировщиком, и в случае отказа перезапускаются сразу все процессы. Существуют +некоторые обходные решения, которые позволяют перезапустить только часть +процессов cite:meyer2012radic, восстановив их на других узлах, однако это +может привести к перегрузке, если на этих узлах уже запущены другие задачи. +Теоретически, перезапуск процесса необязателен если задача может быть +продолжена на меньшем количестве узлов, но библиотека передачи сообщений не +позволяет изменять количество параллельных процессов во время работы программы, +и большинство программ все равно предполагают, что это значение является +константой, и используют его для распределения нагрузки между узлами. Таким +образом, не существует простого способа обеспечения отказоустойчивости на +уровне библиотеки передачи сообщений кроме как путем перезапуска всех +параллельных процессов из контрольной точки восстановления. + +В то же время, существует возможность продолжить выполнение задачи на меньшем +количестве узлов, чем было изначально выделено под нее планировщиком. В этом +случае нагрузка должна быть динамически перераспределена между оставшимися +узлами. Несмотря на то что динамическое распределение нагрузки было реализовано +в поверх библиотеки передачи сообщений в ряде +работ cite:bhandarkar2001adaptive,lusk2010more, оно никогда не применялось в +задаче обеспечения отказоустойчивости. В этом разделе исследуются методы +обеспечения отказоустойчивости при выходе из строя подчиненных и главных узлов +и показывается, как приемы объектно-ориентированного программирования могут +быть использованы для сохранения минимального состояния программы, необходимого +для ее перезапуска, в иерархии объектов, а не в глобальных и локальных +переменных. + +**** Иерархия объектов вычисления. +Для распределения нагрузки узлы кластера объединяются в +древовидную иерархию. Нагрузка распределяется между непосредственными соседями +узла, так что при запуске задачи на подчиненном узле главный узел также +получают часть нагрузки. Это делает систему симметричной и легкой в +обслуживании: на каждом узле установлен один и тот же набор программного +обеспечения, что позволяет заменить один узел другим при выходе из строя +первого. Похожее архитектурное решение используется в хранилищах типа +"ключ-значение" cite:anderson2010couchdb,lakshman2010cassandra для +обеспечения отказоустойчивости при выходе из строя одного из узлов, однако +автору неизвестны планировщики задач, которые используют данный подход. + +Каждая программа, запущенная поверх иерархии узлов состоит из +/вычислительных объектов/ --- объектов, которых содержат данные и код для +их обработки. Для эффективного использования параллелизма, предоставляемого +кластером и многопроцессорной машиной, объект может создать подчиненные +(дочерние) объекты, которые система автоматически распределит сначала между +доступными процессорными ядрами, затем между подчиненными узлами кластера. Сама +программа также является вычислительным объектом, который либо решает +прикладную задачу последовательно, либо создает подчиненные объекты для +параллельного решения. + +В отличие от функции ~main~ в программах на основе библиотеки передачи +сообщений, первый вычислительный объект выполняется только на одном узле, а +дополнительные узлы используются либо при переполнении очереди объектов +текущего узла, либо при явном указании в коде программы. Такая архитектура +позволяет использовать произвольное количество узлов для запуска задачи и +динамически менять это количество во время ее выполнения. Похожий принцип +выполнения задач используется в системах обработки больших объемов +данных cite:dean2008mapreduce,vavilapalli2013yarn --- при запуске задаче не +требуется указывать количество узлов, вместо этого система сама выбирает узлы, +на которых будет выполняться задача, в зависимости физического расположения +входных файлов. + +С математической точки зрения вычислительный объект $K$ может быть определен +как векторнозначный функционал, отображающий один вычислительный объект на +$n$-компонентный вектор вычислительных объектов: +\begin{equation*} + K(f): \mathbb{K} \rightarrow \mathbb{K}^n + \qquad + \mathbb{K}^n = \left\{ f: \mathbb{K} \rightarrow \mathbb{K}^n \right\}. +\end{equation*} +Специальный объект $\mathbb{O}: \mathbb{K} \rightarrow \mathbb{K}^0$ +используется для остановки рекурсии, и передается в качестве аргумента главному +(первому созданному) объекту программы. Аргумент функционала интерпретируется +следующим образом. +- Если текущий объект является только что созданным объектом, то аргумент + функционала --- это главенствующий над ним объект (родитель). +- Если текущий объект является родителем объекта, который его породил или + родителем какого-либо другого объекта, то аргумент функционала --- объект, + которые его породил. + +Объекты обрабатываются в цикле, который начинается с вызова функции главного +объекта программы, затем вызываются функции всех порожденных им объектов. Цикл +продолжается до тех пор пока функция какого-либо объекта не вернет +$\mathbb{O}$. Поскольку вызов функции может породить сразу несколько объектов, +они выполняются параллельно, что приводит к быстрому заполнению пула объектов, +которые можно выполнять в произвольном порядке. Несколько потоков одновременно +выбирают из пула объекты для обработки, и при переполнении пула объекты могут +быть переданы на другие узлы кластера без явного указания в исходном коде +программы. + +Вычислительные объекты реализованы в виде замыканий (функторов) --- +объектов-функций, которые сохраняют в себе аргументы, ссылку на породивший их +объект и данные из предметной области задачи. Данные обрабатываются либо при +выполнении объекта, либо для параллельной обработки создаются дочерние объекты. +Когда обработка завершена, родительский объект вызывается с дочерним объектов в +качестве аргумента для сбора результатов обработки. + +**** Выход из строя одного узла. +Наиболее распространенная стратегия при выходе из строя подчиненного узла --- +перезапуск выполнявшихся на нем объектов на рабочих узлах. Этой стратегии +следует язык Erlang для перезапуска подчиненных +процессов cite:armstrong2003thesis. Для того что реализовать этот метод в +рамках иерархии вычислительных объектов необходимо сохранять каждый объект +передаваемый на другие узлы кластера. В случае отказа одного из узлов, на +которые были переданы объекты, соответствующие их копии извлекаются из очереди +на перераспределяются между оставшимися узлами без какой-либо дополнительной +обработки. Если больше узлов не осталось, то объекты перенаправляются в +локальную очередь. В отличие от "тяжеловесного" метода контрольных точек +восстановления, древовидная иерархия узлов в паре с иерархией объектов позволяет +автоматически продолжить выполнение программы при выходе из строя одного из +узлов без перезапуска каких-либо процессов задачи. + +Возможная стратегия при выходе из строя узла, на котором хранится главный +вычислительный объект задачи, заключается в копировании этого объекта на +резервный узел и синхронизировать любые изменения между двумя копиями объекта +посредством распределенных транзакций. Однако, эта стратегия не соотносится с +асинхронностью вычислительных ядер и слишком сложна в реализации. На практике, +оказывается, что главный объект программы обычно не создает больше одного +дочернего объекта, каждый из которых представляет собой последовательный шаг +вычислений (внутри которого может быть, а может не быть параллельных этапов). +Поскольку шаги последовательны, то одновременно может существовать не более +одного дочернего объекта, что позволяет упростить синхронизацию состояния +главного объекта программы. Для этого главный объект передается на подчиненный +узел вместе со своим дочерним объектом. Тогда при выходе из строя узла, на +котором была запущена программа, резервный узел автоматически восстанавливает +состояние главного объекта из копии, когда дочерний объект завершает свою +работу. + +Описанный выше подход предназначен только для объектов, у которых нет +объекта-родителя и которые создают по одному дочернему объекту за раз. Это +означает, что метод работает как контрольная точка восстановления, которая +сохраняет состояние только между последовательными шагами вычислений (когда оно +занимает минимальный объем памяти) и которая для сохранения состояния +использует оперативную память другого узла кластера, а не диск. + **** Обеспечение высокой доступности. +**** Программная реализация. +Из соображений эффективности методы обеспечения отказоустойчивости были +реализованы во фреймворке на языке C++: с точки зрения автора язык C слишком +низкоуровневый для написания распределенных программ, а использование языка +Java влечет за собой накладные расходы, и не популярно в высокопроизводительных +вычислениях. Для того чтобы использовать фреймворка без планировщика задач +необходимо создать сервис, который бы автоматически обновлял состояние +древовидной иерархии узлов и предоставлял программный интерфейс для запуска +задач на ней. На данный момент фреймворк запускает сервис и приложение в одном +процессе. Фреймворк называется "Фабрика" и находится на этапе проверки +концепции. + +**** Результаты тестирования. +Методы отказоустойчивости были протестированы на физическом кластере +(см. [[tab:cluster]]) на примере программы, генерирующей взволнованную +морскую поверхность, подробно описанной +в cite:autoreg-stab,autoreg2011csit,autoreg1,autoreg2 и в данной работе. +Программа состоит из серии фильтров, каждый из которых применяется к результату +работы предыдущего. Некоторые из фильтров применяются параллельно, так что вся +программа состоит из последовательно выполняющихся больших шагов, некоторые из +которых внутри реализованы параллельно из соображений эффективности. Только +наиболее ресурсоемкий этап программы (генерация взволнованной морской +поверхности) выполняется параллельно на всех узлах, другие этапы выполняются +параллельно на всех процессорных ядрах главного узла. + +#+name: tab:cluster +#+caption: Конфигурация кластера. +| CPU | Intel Xeon E5440, 2.83GHz | +| RAM | 4Gb | +| HDD | ST3250310NS, 7200rpm | +| Кол-во узлов | 12 | +| Кол-во ядер на узел | 8 | + +Программа была переписана под новую версию фреймворка, что потребовало лишь +небольших изменений исходного кода для корректной обработки выхода из строя +узла с главным объектом: главный объект был помечен, чтобы фреймворк смог +передать его на подчиненный узел. Другие изменения исходного кода были связаны +с изменением программного интерфейса фреймворка. Таким образом, обеспечение +отказоустойчивости, в основном, прозрачно для программиста и требует лишь +маркировки главного объекта для его репликации на резервный узел. + +В ряде экспериментов производительность новой версии программы была измерена +при выходе из строя различных типов узлов во время выполнения программы (номера +пунктов соответствуют номерам графиков [[fig:benchmark]]): +- без выхода из строя узлов, +- выход из строя подчиненного узла (на котором генерируется часть взволнованной + поверхности), +- выход из строя главного узла (на котором запускается программа), +- выход из строя резервного узла (на который копируется главный объект + программы). +Древовидная иерархия узлов со значением ветвления равного 64 использовалась в +экспериментах, для того чтобы удостовериться, что все подчиненные узлы соединены +с первым узлом подсети кластера. При каждом запуске программы главный объект +запускался не на главном узле, чтобы оптимально отобразить иерархию объектов на +иерархию узлов (наложить одну на другую). Узел-жертва выводился из строя по +прошествии фиксированного временного интервала после запуска программы равного +примерно $1/3$ времени работы программы на одном узле. Способ запуска для +каждого эксперимента представлен в [[tab:benchmark]] ("корень" и "лист" относятся к +положению узла в древовидной иерархии). Результаты экспериментов приведены на +[[fig:benchmark]] и [[fig:slowdown]]. + +Графики 2 и 3 на [[fig:benchmark]] показывают, что производительность в +случае выхода из строя главного и подчиненного узлов примерно одинакова. В +случае отказа главного узла резервный узел сохраняет копию главного объекта и +восстанавливает главный объект из нее, когда не обнаруживает, что главный узел +вышел из строя. В случае отказа подчиненного узла, главный узел +перераспределяет невернувшиеся объекты между оставшимися подчиненными узлами. В +обоих случая состояние главного объекта программы не теряется, а значит не +тратится время на его восстановление, что объясняет схожую производительность. + +График 4 на [[fig:benchmark]] показывает, что производительность в случае +выхода из строя резервного узла гораздо ниже, чем в других случаях. Это +происходит, потому что главный узел сохраняет состояние только текущего +последовательного этапа программы, в то время как резервный узел не только +хранит копию этого состояния, но и выполняет параллельные части этапа вместе с +другими подчиненными узлами. Так что, когда резервный узел выходит из строя, +главный узел начинает выполнение текущего этапа с самого начала. + +#+caption: Параметры экспериментов. +#+name: tab:benchmark +| Номер эксп. | Главный узел | Узел-жертва | Время до выхода из строя, сек. | +| 1 | корень | | | +| 2 | корень | лист | 10 | +| 3 | корень | лист | 10 | +| 4 | корень | лист | 10 | + +Для оценки количества времени, которое теряется при выходе из строя одного из +узлов, можно поделить общее время работы программы со сбоем на время работы +программы без сбоев, но с количеством узлов минус один. Это отношение +представлено на [[fig:slowdown]]. Разница в производительности в случае +выхода из строя главного узла и подчиненного узла находится в пределах 5\%, а в +случае выхода из строя резервного узла --- в пределах 50\% для количества узлов +меньше 6\footnote{Измерение разницы для большего количества узлов не имеет +смысла, поскольку программа завершается еще до наступления сбоя.}. Разница в +50\% больше, чем $1/3$ времени работы программы, после которого происходит +сбой, однако отказ резервного узла требует некоторого времени, чтобы быть +обнаруженным другими узлами. Сбой узла обнаруживается только тогда, когда +подчиненный объект завершает свое выполнение и пытается вернуться на исходный +узел к родителю. Мгновенное обнаружение сбоя узла требует остановки выполнения +объектов, что может быть неприменимо для программ со сложной логикой. + +#+name: fig:benchmark +#+begin_src R +# TODO +#+end_src + +#+caption: Производительность программы генерации взволнованной морской поверхности при различных типах сбоев узлов. +#+RESULTS: fig:benchmark + +Результаты экспериментов позволяют сделать вывод о том, что /не важно, +вышел ли из строя главный узел или подчиненный, итоговое время работы программы +будет примерно равно времени ее работы без сбоев, но с уменьшенным на единицу +количеством узлов/, однако, в случае выхода из строя резервного узла теряется +гораздо больше времени. + +#+name: fig:slowdown +#+begin_src R +# TODO +#+end_src + +#+caption: Замедление программы генерации взволнованной морской поверхности при различных типах сбоев по сравнению с запуском без сбоев но с уменьшенным на единицу количеством узлов. +#+RESULTS: fig:slowdown + +**** Выводы по результатам тестирования. +Проведенные эксперименты показывают, что параллельной программе необходимо +иметь несколько последовательных этапов выполнения, чтобы сделать ее устойчивой +к сбоям узлов. Несмотря на то что вероятность сбоя резервного узла меньше +вероятности сбоя одного из подчиненных узлов, это не повод потерять все данные, +когда выполнявшаяся несколько дней задача почти завершилась. В общем случае, +чем больше последовательных этапов вычислений содержит программа, тем меньше +времени потеряется в случае сбоя резервного узла, и, аналогично, чем больше +параллельных частей содержит каждый этап, тем меньше времени потеряется при +сбое главного или подчиненного узла. Другими словами, /чем больше +количество узлов, на которое масштабируется программа, тем она более устойчива +к сбою оборудования/. + +В проведенных экспериментах узел, на котором запускается программа, выбирается +вручную, чтобы совместить иерархию объектов и иерархию узлов, однако, такой +подход не применим в реальных системах. Разработанный фреймворк должен делать +это автоматически и эффективно распределять нагрузку между подчиненными узлами +в независимости от местоположения главного узла в иерархии: выделение одного и +того же узла в качестве главного для запуска нескольких приложений уменьшает +общую отказоустойчивость системы. + +Хотя это неочевидно из экспериментов, Фабрика не только обеспечивает +отказоустойчивость, но и позволяет автоматически вводить новые узлы в кластер и +распределять на них часть нагрузки уже запущенных программ. В контексте +фреймворка этот процесс тривиален, поскольку не требует перезапуска +незавершившихся объектов и копирования их состояния, и не изучался +экспериментально в данной работе. + +Теоретически отказоустойчивость, основанная на иерархии может быть реализована +поверх библиотеки передачи сообщений без потери общности. Хотя использование +незагруженных узлов заместо вышедших из строя в рамках такой библиотеки +представляет определенную сложность, поскольку количество узлов, на которых +запущена программа фиксировано, но выделение достаточно большого количества +узлов для программы будет достаточно для обеспечения отказоустойчивости. + +Слабым местом описанных методов является период времени, начиная с отказа +главного узла и заканчивая обнаружением сбоя подчиненным узлом. Если до момента +восстановления главного объекта из копии резервный узел выходит из строя, то +состояние выполнения программы полностью теряется без возможности его +восстановить, кроме как перезапуском с самого начала. Длина этого опасного +промежутка времени может быть уменьшена, но исключить его полностью невозможно. +Этот результат согласуется с исследованиями теории "невыполнимости" в рамках +которой доказывается невозможность распределенного консенсуса с хотя бы одним +процессом, дающим сбой cite:fischer1985impossibility и невозможность надежной +передачи данных в случае сбоя одного из узлов cite:fekete1993impossibility. + * Заключение **** Итоги исследования. В изучении возможностей математического аппарата для имитационного моделирования