Отказоустойчивость¶
Страница отвечает на вопрос «что произойдёт, если это упадёт» по каждому компоненту. Формулировки намеренно прямые: там, где отказоустойчивости нет, так и написано.
Сводка¶
| Компонент | Переживает отказ узла | Что происходит при отказе |
|---|---|---|
frontend |
Да, при нескольких репликах | Интерфейс недоступен, данные не страдают |
backend |
Да, при нескольких репликах | API недоступен, загрузка отчётов отклоняется |
worker |
Да, при нескольких репликах | Обработку подхватывает backend — медленнее, но не останавливается |
| PostgreSQL | Нет в поставляемой конфигурации | Останавливается всё |
| Хранилище отчётов | Только сам том | Приём новых отчётов прекращается |
DomainScope |
Нет, экземпляр один | Обследование периметра приостанавливается |
| OpenVAS, OWASP ZAP | Нет, экземпляры одиночные | Соответствующие проверки не выполняются |
Компоненты без состояния¶
frontend отдаёт собранную статику. Реплик может быть сколько угодно,
согласование между ними не требуется.
backend не хранит состояния между запросами: сессия пользователя — это
подписанный токен, а не запись в памяти процесса. Реплики можно добавлять и
убирать свободно, липкие сессии на балансировщике не нужны.
Отдельного пояснения требуют периодические задачи. Их планировщики работают в процессе backend и не выбирают лидера — тикает каждая реплика. Это безопасно, потому что постановка задач в очередь дедуплицируется по временному окну: окно заведомо короче интервала тика (например, 55 минут при часовом), поэтому вторая и последующие реплики не создают дубликат, а попадают в уже поставленную задачу.
Практический вывод: несколько реплик backend не приводят к двойному выполнению периодических задач. Проверять это отдельно не требуется.
worker берёт задачи из общей очереди в базе. Тот же обработчик работает
и внутри backend, поэтому очередь разбирается, даже если ни одной реплики
worker не осталось. Реплики разбирают задачи
конкурентно; задача, чей исполнитель погиб, возвращается в очередь и
выполняется повторно. Отсюда важное свойство: доставка «не менее одного
раза». Задача может выполниться дважды, если процесс умер после совершения
действия, но до отметки о завершении. Обработчики к этому готовы, но у
внешних систем это может проявиться: например, повторным уведомлением.
PostgreSQL как единственная точка отказа¶
База данных хранит и данные, и очередь задач. Её потеря останавливает решение целиком: интерфейс не открывается, загрузка отчётов отклоняется, фоновая обработка не идёт.
Поставляемые манифесты разворачивают один экземпляр PostgreSQL без репликации и без автоматического переключения. Это осознанное упрощение для пилота, а не готовая к промышленной эксплуатации конфигурация.
Для промышленной среды используйте внешнюю базу с тем уровнем доступности,
который у вас принят: управляемый сервис облачного провайдера либо кластер с
репликой и переключением. Hub подключается к внешней базе обычными
переменными DB_* — от него ничего специального не требуется.
Что необходимо в любом случае:
- Резервные копии базы — ежедневно, с хранением не менее двух недель.
- Проверка восстановления — раз в квартал развернуть копию на отдельном стенде и убедиться, что Hub стартует и видит данные. Непроверенная резервная копия равносильна её отсутствию.
- Наблюдение за местом на диске — переполнение тома базы останавливает запись.
Хранилище отчётов¶
Загруженные файлы отчётов лежат на отдельном томе backend. Потеря тома не приводит к потере находок: находки уже разобраны и лежат в базе. Теряется возможность посмотреть исходный файл отчёта.
Переполнение тома — более неприятный отказ: файл не сохраняется, и загрузка
завершается ошибкой. Место освобождает периодическая очистка по срокам
хранения (CLEANUP_RETENTION_*), но она не поможет, если сроки заданы
слишком щедро для имеющегося объёма. Следите за заполнением тома.
Том отчётов и разбор
В поставляемых манифестах у backend и worker разные тома, а том worker'а вообще временный. Поэтому отчёт, доставшийся worker'у, читается не с диска, а из базы, куда его содержимое сохраняется при загрузке. Последствия для планирования объёма базы и памяти описаны в Известных ограничениях.
Провайдер SSO¶
Если вход настроен через внешний провайдер, его недоступность мешает новым входам. Уже вошедшие пользователи продолжают работать, пока действует их токен обновления — по умолчанию до 7 суток, при условии что вкладка периодически его обновляет.
Недоступность провайдера при старте backend не мешает запуску: сведения о провайдере получаются по мере надобности, и сервис поднимается даже с недостижимым провайдером. Кнопки входа при этом появятся не сразу.
На случай полной недоступности провайдера имеет смысл заранее держать работоспособной хотя бы одну учётную запись администратора — способ зависит от выбранного режима входа.
Внешние интеграции¶
Отказ любой из них не останавливает Hub: находки продолжают приниматься и обрабатываться.
| Интеграция | Что происходит при недоступности |
|---|---|
| Jira | Задача не создаётся, задание повторяется по нарастающей задержке |
| Telegram, MAX, Mattermost, SMTP | Уведомление не доставляется, задание повторяется |
| LLM-сервис | Находка остаётся без разбора моделью, статус не меняется |
| NetBox | Синхронизация периметра пропускает цикл |
| Сервер лицензий | Проверка пропускается; работа не блокируется |
Повторы выполняются с нарастающей задержкой. Задание, исчерпавшее попытки, остаётся в очереди в состоянии ошибки — его видно в интерфейсе управления заданиями, и повтор можно запустить вручную.
DomainScope и сканеры¶
DomainScope — одиночный процесс с циклами по расписанию. Второй экземпляр поверх той же базы не предусмотрен: два процесса начнут выполнять одни и те же циклы одновременно. При падении обследование приостанавливается до подъёма; уже переданные в Hub находки не страдают.
OpenVAS и OWASP ZAP тоже разворачиваются одиночными экземплярами. Их недоступность означает, что соответствующие проверки не выполняются, — на работу Hub это не влияет.
Обновления без простоя¶
Backend, worker и frontend обновляются последовательной заменой реплик — при двух и более репликах API остаётся доступным.
Исключение — миграции схемы базы данных. Они применяются при старте backend под блокировкой, чтобы одновременный запуск нескольких реплик не привёл к параллельному изменению схемы: первая реплика мигрирует, остальные ждут. Отдельного шага в процедуре обновления это не требует, но означает, что обновление с миграцией занимает больше времени, чем обычная замена реплик, и на это время старая и новая схемы должны быть совместимы. Подробнее: Обновления.
Чего в решении нет¶
Честный перечень того, что при необходимости придётся строить снаружи:
- Развёртывание в нескольких зонах или регионах. Решение рассчитано на один кластер или один узел.
- Автоматическое переключение базы данных. Обеспечивается вашей инфраструктурой.
- Гарантия «ровно один раз» для фоновых задач. Гарантия — «не менее одного раза».
- Резервный экземпляр DomainScope. Второй экземпляр на той же базе работать не рассчитан.