Поддержка отказоустойчивости исполнения т-приложений

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

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

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

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

Мы будем предполагать, что прикладная программа написана в функциональном стиле, и в случае его расширения прикладной программист так же точно отвечает за отказоустойчивость своей программы при использовании отказоустойчивой OpenTS, как и за простые корректность и детерминированность результатов счета в случае обычной Т-системы.

Неготовые значения и незавершенные по причине сбоя вычисления

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

Для того чтобы у прикладного программиста появилась возможность самостоятельно принимать решение об обработке сбоев, мы пополним диаграмму состояний неготового значения еще одним состоянием — «незавершенное». Это состояние является альтернативой готовому состоянию и отличается от него следующими ключевыми свойствами:

  • Неготовое значение становится незавершенным, если его вычисление было остановлено вследствие сбоя.
  • Незавершенное значение является готовым в том смысле, что попытка прямого получения находящегося в нем реального значения не приводит к остановке процесса, но ведет к исключительной ситуации в программе. То есть, значение можно получить, но если сделать это непосредственно, то произойдет исключение.
  • В случае, когда прикладная программа использует примитив языка T++ twait(), то она получает событие, означающее что величина готова, но вычисление не было завершено. В этом случае она может продолжать счет, предприняв то или иное действие в соответствии с выбранной «заказной» моделью обработки сбоя.

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

Вектор перерождений

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

Если ограничить значение счетчика перерождений некой разумной величиной (например, типом данных int), то можно хранить вектор перерождений в массиве байт (каждый элемент содержит 31 бит на порядковый номер и 1 бит на текущий статус работоспособности).

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

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

Вектор посещений

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

Очевидно, вектор посещений является характеристикой Т-функции и должен передаваться (и корректно при этом модифицироваться) вместе с ней в случае миграции.

Практика. Виртуализация бизнес-критичных приложений, Олег Ульянов


Похожие статьи.

Понравилась статья? Поделиться с друзьями: