Обеспечение высокой готовности системы

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

Термин "высокая готовность"
Обеспечение высокой готовности средствами ОС
Интегрированные свойства высокой готовности
Специализированные модули
Клиентская библиотека
Пример сценария восстановления доступа
Мендежер высокой готовности (HAM)
HAM и его дублер (Guardian)
Иерархия HAM
Сущности (entities)
Условия (conditions)
Действия (actions)
Альтернативные действия (alternate actions)
Публикация автономно выявленных условий
Изменения состояния
Другие условия
Подписка на автономно опубликованные условия
Триггер по изменению состояния
Триггер по определенному опубликованному условию
HAM как файловая система
Многоэтапное восстановление
Программные интерфейсы HAM

Термин "высокая готовность"

Термин высокая готовность (англ. High Availablity, HA) обычно используется в сфере телекоммуникаций и других индустриях для обозначения способности системы сохранять рабочее состояние без продолжительных периодов простоя. Знаменитая метрика готовности пять девяток относится к проценту времени безотказной работы, который система может поддерживать в течение года — 99,999% безотказной работы составляет около пяти минут простоя в год.

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

Обеспечение высокой готовности средствами ОС

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

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

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

Интегрированные свойства высокой готовности

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

Резюмируя сказанное можно заметить, что ЗОСРВ «Нейтрино» изначально обладает рядом важных для высокой готовности свойств:

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

Специализированные модули

ЗОСРВ «Нейтрино» имеет несколько компонентов, которые позволяют разработчикам упростить построение и обслуживание эффективных систем высокой готовности:

Клиентская библиотека

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

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

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

Пример сценария восстановления доступа

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

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

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <ha/cover.h>
#define TESTFILE "/net/machine99/home/test/testfile"
typedef struct handle {
int nr;
int curr_offset;
} Handle;
int recover_conn( int oldfd, void *hdl )
{
int newfd;
Handle *thdl;
thdl = (Handle *)hdl;
newfd = ha_reopen( oldfd, TESTFILE, O RDONLY );
if ( newfd >= 0 )
{
/* Перемещение на предыдущую известную позицию в файле */
lseek( newfd, thdl->curr_offset, SEEK SET );
/* Увеличение значения счетчика успешных восстановлений */
(thdl->nr)++;
}
return (newfd);
}
int main( int argc, char *argv[] )
{
int status;
int fd;
int fd2;
Handle hdl;
char buf[80];
hdl.nr = 0;
hdl.curr_offset = 0;
/* Открывается соединение. Для восстановления используется recover_conn()
* и hdl передается ей в качестве параметра */
fd = ha open( TESTFILE, O RDONLY, recover conn, (void *)&hdl, 0 );
if ( fd < 0 )
{
printf( "could not open file\n" );
exit( -1 );
}
status = read( fd, buf, 15 );
if ( status < 0 )
{
printf( "error: %s\n", strerror( errno ) );
exit( -1 );
} else
hdl.curr_offset += status;
fd2 = ha_dup( fd );
/* fs-nfs3 перезапускается после ошибки. Сетевые точки монтирования
* перемонтируются, предыдущий fd освобождается */
sleep( 18 );
/* При попытке чтения из дублированного fd произойдет ошибка, после
* чего выполняется восстановление с помощью recover_conn() */
status = read( fd, buf, 15 );
if ( status < 0 )
{
printf( "error: %s\n", strerror( errno ) );
exit( -1 );
} else
hdl.curr_offset += status;
printf( "total recoveries, %d\n", hdl.nr );
ha_close( fd );
ha_close( fd2 );
exit( 0 );
}

Поскольку библиотека функций-оберток обрабатывает вызовы нижнего уровня вроде MsgSend*(), большинство стандартных библиотечных функций ( read(), write(), printf(), scanf() и т.д.) также автоматически поддерживают высокую готовность. Библиотека содержит функцию ha_dup(), которая в контексте соединений высокой готовности семантически эквивалента стандартной функции dup(). Можно заменять функции восстановления в процессе существования соединения, что значительно упрощает задачу разработки настраиваемых механизмов восстановления.

Мендежер высокой готовности (HAM)

Менеджер высокой готовности (High Availability Manager, HAM) обеспечивает механизм контроля системных процессов и служб. Другими словами, это программный сторожевой таймер, который способен выполнять многоэтапное восстановление в тех случаях, когда системные службы или процессы дают сбой, не отвечают или оказываются в состоянии, в котором не могут обеспечить необходимый уровень обслуживания. HAM использует простой механизм публикации и подписки для передачи необходимых системных событий между теми или иными ее компонентами. Посредством автоматической интеграции в сетевой механизм Qnet среда высокой готовности прозрачным образом расширяет локальный механизм мониторинга, превращая его в распределенный по сети.

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

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

HAM и его дублер (Guardian)

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

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

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

Иерархия HAM

Менеджер высокой готовности оперирует тремя основными понятиями:

Сущности (entities)

Сущности (Entities) — это основные предметы наблюдения/контроля в системе. Сущность, фактически, это процесс (pid). Как нормальные процессы, все сущности имеют уникальный идентификатор. С каждой сущностью связано символьное имя, которое служит для ссылок на данную конкретную сущность. Имена, связанные с сущностями, естественно, являются уникальными для всей системы. Менеджеры в настоящее время связаны с узлами, поэтому правило уникальности относится к узлу. Как будет рассмотрено далее, это требование уникальности очень напоминает схему именования, применяемую в иерархических файловых системах.

Существует три типа сущностей:

Условия (conditions)

Условия связаны с сущностями. Условие определяет состояние сущности.

Условие Описание
CONDDEATH Сущность умерла
CONDABNORMALDEATH Сущность умерла неестественной смертью. При всякой смерти сущности это условие запускается механизмом, который создает "посмертный" дамп
CONDDETACH Отсоединение сущности, которая контролировалась менеджером высокой готовности, в результате чего контроль завершается
CONDATTACH Сущность, для которой ранее был создан заменитель (т.е. некоторый процесс подписался на события, связанные с этой сущностью), присоединилась к системе. Одновременно это означает запуск контроля данной сущности со стороны менеджера высокой готовности
CONDBEATMISSEDHIGH Сущность пропустила отправку квитанции работоспособности, заданную для условий с "высокой" серьезностью ("high" severity)
CONDBEATMISSEDLOW Сущность пропустила отправку квитанции работоспособности, заданную для условий с "низкой" серьезностью ("low" severity)
CONDRESTART Сущность была перезапущена. Это условие становится истинным после того, как сущность успешно перезапускается
CONDRAISE Внешне-определяемое условие передается менеджеру высокой готовности. Подписчики могут связывать действия с этими условиями
CONDSTATE Сущность сообщает менеджеру высокой готовности о смене состояния. Подписчики могут связывать действия теми или иными изменениями состояния
CONDANY Этот тип условия подходит для любых условий. Он может использоваться для связывания некоторых действий с одним из множества условий

Для приведенных в таблице условий (кроме CONDSTATE, CONDRAISE и CONDANY) менеджер высокой готовности является публикатором (publisher), так как он автоматически определяет и/или запускает эти условия. Что касается условий CONDSTATE и CONDRAISE, то их публикуют менеджеру высокой готовности внешние обнаружители.

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

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

Действия (actions)

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

Действие Описание
ham_action_restart() Это действие перезапускает сущность
ham_action_execute() Выполняет заданную команду (например, запустить процесс)
ham_action_notify_pulse() Извещает некоторый процесс о возникновении данного условия. Это извещение отправляется с помощью импульса со значением, заданным процессом, который запросил такое извещение
ham_action_notify_signal() Извещает некоторый процесс о возникновении данного условия. Это извещение отправляется с помощью сигнала реального времени со значением, заданным процессом, который запросил такое извещение
ham_action_notify_pulse_node() Аналогично действию ham_action_notify_pulse() (см. ранее), за исключением того, что имя узла, заданное в качестве получателя импульса, может быть определено в виде полного имени (fully qualified node name)
ham_action_notify_signal_node() Аналогично действию ham_action_notify_signal() (см. ранее), за исключением того, что имя узла, заданное в качестве получателя сигнала, может быть определено в виде полного имени
ham_action_waitfor() Позволяет добавлять задержки между действиями в последовательности. Также с помощью данного действия можно ожидать появление указанных имен в именном пространстве
ham_action_heartbeat_healthy() Сбрасывает состояние механизма отправки квитанций работоспособности для сущности, которая пропустила отправку квитанции и тем самым вызвала соответствующее условие, но в данный момент уже восстановила свою работу
ham_action_log() Передает данное условие механизму регистрации событий

Действия также связываются с символьными именами, которые должны быть уникальными внутри данного условия.

Альтернативные действия (alternate actions)

Что происходит, если само действие дает сбой? Можно задать альтернативный список действий, которые должны выполняться для восстановления после таких сбоев. Эти альтернативные действия связываются с основными действиями с помощью нескольких функций:

Публикация автономно выявленных условий

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

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

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

Изменения состояния

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

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

Для того чтобы известить менеджер высокой готовности об изменении состояния, компоненты могут использовать функцию ham_entity_condition_state(). HAM получает информацию о следующем состоянии при его изменении, поскольку только эта информация необходима для него. Затем HAM запускает событие по условию изменения состояния, на которое другие компоненты могут подписаться с помощью API-вызова ham_condition_state() (см. далее).

Другие условия

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

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

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

Триггер по изменению состояния

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

Триггер по определенному опубликованному условию

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

HAM как файловая система

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

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

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

Многоэтапное восстановление

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

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

Другой пример: произошел сбой сетевого менеджера io-pkt-*. Можно дать менеджеру высокой готовности инструкцию перезапустить сетевой менеджер и подключить соответствующие сетевые диски (а также, если необходимо, другие службы, которые зависят от сетевых служб).

Программные интерфейсы HAM

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

Программный интерфейс менеджера высокой готовности предоставляет следующий набор функций:

Функция Описание
ham_action_control() Выполнить операции контроля для данного действия
ham_action_execute() Добавить действие к условию
ham_action_fail_execute() Добавить другое действие, которое должно быть выполнено при сбое соответствующего действия
ham_action_fail_log() Добавить сообщение в журнал действий
ham_action_fail_notify_pulse() Добавить действие отправки импульса при сбое соответствующего действия
ham_action_fail_notify_pulse_node() Добавить действие отправки импульса заданному узлу при сбое соответствующего действия
ham_action_fail_notify_signal() Добавить действие отправки сигнала при сбое соответствующего действия
ham_action_fail_notify_signal_node() Добавить действие отправки сигнала заданному узлу при сбое соответствующего действия
ham_action_fail_waitfor() Добавить действие ожидания, которое должно быть выполнено при сбое соответствующего действия
ham_action_handle() Получить дескриптор для действия, находящегося в условии, которое создано внутри сущности
ham_action_handle_node() Используя имя узла, получить дескриптор для действия, находящегося в условии, которое создано внутри сущности
ham_action_handle_free() Освободить ранее полученный дескриптор действия, находящегося в условии, которое создано внутри сущности
ham_action_heartbeat_healthy() Обнулить состояние счетчика квитанций работоспособности
ham_action_log() Добавить сообщение в журнал действий
ham_action_notify_pulse() Добавить к условию действие отправки импульса
ham_action_notify_pulse_node() Добавить к условию действие отправки импульса, используя имя узла
ham_action_notify_signal() Добавить к условию действие отправки сигнала
ham_action_notify_signal_node() Добавить к условию действие отправки сигнала, используя имя узла
ham_action_remove() Удалить действие из условия
ham_action_restart() Добавить к условию действие перезапуска
ham_action_waitfor() Добавить к условию действие ожидания
ham_attach() Присоединить сущность
ham_attach_node() Присоединить сущность, используя имя узла
ham_attach_self() Присоединить приложение как самоприсоединяемую сущность
ham_condition() Связать вызов условия с возникновением некоторого события
ham_condition_control() Выполнить операции контроля для данного условия
ham_condition_handle() Получить дескриптор для условия в сущности
ham_condition_handle_node() Используя имя узла, получить дескриптор для условия в сущности
ham_condition_handle_free() Освободить ранее полученный дескриптор условия в сущности
ham_condition_raise() Присоединить условие, связанное с условием вызова условия, которое вызывается сущностью, вызывающей условие
ham_condition_remove() Удалить условие из сущности
ham_condition_state() Присоединить условие, связанное с условием изменения состояния, которое вызывается сущностью, сообщающей об изменении состояния
ham_connect() Соединиться с менеджером высокой готовности
ham_connect_nd() Соединиться с удаленным менеджером высокой готовности
ham_connect_node() Используя имя узла, соединиться с удаленным менеджером высокой готовности
ham_detach() Отсоединить сущность от менеджера высокой готовности
ham_detach_name() Отсоединить сущность от менеджера высокой готовности, используя имя сущности
ham_detach_name_node() Отсоединить сущность от менеджера высокой готовности, используя имя сущности и имя узла
ham_detach_self() Отсоединить самоприсоединяемую сущность от менеджера высокой готовности
ham_disconnect() Разорвать связь с менеджером высокой готовности
ham_disconnect_nd() Разорвать связь с удаленным менеджером высокой готовности
ham_disconnect_node() Разорвать связь с удаленным менеджером высокой готовности, используя имя узла
ham_entity() Создать объекты-заменители сущности в менеджере высокой готовности
ham_entity_condition_raise() Вызвать условие
ham_entity_condition_state() Сообщить менеджеру высокой готовности об изменении состояния
ham_entity_control() Выполнить операции контроля для сущности в менеджере высокой готовности
ham_entity_handle() Получить дескриптор для сущности
ham_entity_handle_node() Получить дескриптор для сущности, используя имя узла
ham_entity_handle_free() Освободить ранее полученный дескриптор сущности
ham_entity_node() Создать объекты-заменители сущности в менеджере высокой готовности, используя имя узла
ham_heartbeat() Отправить квитанцию работоспособности менеджеру высокой готовности
ham_stop() Остановить менеджер высокой готовности
ham_stop_nd() Остановить удаленный менеджер высокой готовности
ham_stop_node() Остановить удаленный менеджер высокой готовности, используя имя узла
ham_verbose() Изменить уровень детализации диагностических сообщений (verbosity) менеджера высокой готовности




Предыдущий раздел: перейти