клиентская библиотека высокой доступности (HA client-side library) для реализации функций-заменителей (cover functions), которые обеспечивают механизмы автоматического и прозрачного восстановления соединений с сервером;
администратор высокой готовности (HA Manager) — "интеллектуальный сторож", который способен выполнять многостадийное восстановление при отказе системных служб или процессов.
Листинг 15.1
#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-nfs2 перезапускается после ошибки.
// сетевые точки монтирования перемонтируются
// предыдущий 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);
}
сущности (entities);
условия (conditions);
действия (actions)
Самоприсоединяемые (self-attached), или "пассивные" сущности (компоненты с поддержкой высокой готовности) — процессы, автоматически отправляющие квитанции работоспособности (heartbeats) администратору высокой готовности, который в результате начинает контролировать их работу. Самоприсоединяемые сущности могут самостоятельно решать, в какой именно точке их жизненного цикла необходимо их контролировать, при каких условиях необходимо выполнять заданные действия и когда контроль должен быть завершен. Другими словами, такой процесс как бы говорит: "В случае моей смерти сделать следующее".
Внешне-присоединяемые (Externally attached), или "активные" сущности (компоненты без поддержки высокой готовности) — обычные процессы (в том числе унаследованные компоненты), которые контролируются системой. Это могут быть любые демоны или службы, состояние которых считается особенно важным. Данный метод полезен для тех случаев, когда, например, процесс A говорит: "Сообщите мне, когда процесс B умрет", при этом процесс B не обязательно должен знать об этом.
Глобальная (Global) сущность — заменитель любой сущности. Глобальная сущность может использоваться для связывания действий с событиями. При возникновении некоторых событий в отношении какой-либо сущности система запускает заданные действия. Термин "глобальный" относится к набору контролируемых сущностей и позволяет процессу сказать что-то вроде: "Когда любой процесс умирает или пропускает отправку квитанции работоспособности, выполните следующее". Глобальную сущность нельзя добавить или удалить, на нее можно только сослаться. Конечно, внутри глобальной сущности можно добавлять или удалять условия, а внутри условий можно добавлять или удалять действия.
Таблица 15.1. Условия
Условие |
Описание |
CONDDEATH |
Сущность умерла |
CONDABNORMALDEATH |
Сущность умерла неестественной смертью12. При всякой смерти сущности это условие запускается механизмом, который создает "посмертный" дамп |
CONDDETACH |
Отсоединение сущности, которая контролировалась администратором высокой готовности, в результате чего контроль завершается |
CONDATTACH |
Сущность, для которой ранее был создан заменитель (т. е. некоторый процесс подписался на события, связанные с этой сущностью), присоединилась к системе. Одновременно это означает запуск контроля данной сущности со стороны администратора высокой готовности |
CONDBEATMISSEDHIGH |
Сущность пропустила отправку квитанции работоспособности, заданную для условий с "высокой" серьезностью ("high" severity) |
CONDBEATMISSEDLOW |
Сущность пропустила отправку квитанции работоспособности, заданную для условий с "низкой" серьезностью ("low" severity) |
CONDRESTART |
Сущность была перезапущена. Это условие становится истинным после того, как сущность успешно перезапускается |
CONDRAISE |
Внешне-определяемое условие передается администратору высокой готовности. Подписчики могут связывать действия с этими условиями |
CONDSTATE |
Сущность сообщает администратору высокой готовности о смене состояния. Подписчики могут связывать действия теми или иными изменениями состояния |
CONDANY |
Этот тип условия подходит для любых условий. Он может использоваться для связывания некоторых действий с одним из множества условий |
Таблица 15.2. Действия
Действие |
Описание |
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() |
Передает данное условие механизму регистрации событий |
Действия также
связываются с символьными именами, которые должны быть
уникальными внутри данного условия.
ham_action_fail_execute()
ham_action_fail_notify_pulse()
ham_action_fail_notify_signal()
ham_action_fail_notify_pulse_node()
ham_action_fail_notify_signal_node()
ham_action_fail_waitfor()
ham_action_fail_log()
публикация информации об изменениях состояния;
публикация информации о других условиях.
Таблица 15.3. Функции администратора высокой готовности
Функция |
Описание |
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) администратора высокой готовности |