Продолжаем тему асинхронности. Предыдущие статьи:
eventual consistency про бизнес-процессы
RPC поверх брокера и его ловушки
Брокер как единая точка отказа: миф о магической отказоустойчивости
Широко распространён миф: «Сделаем через очереди - и система станет устойчивее». Но брокер - это такой же критический компонент, как база данных. Иногда даже более критический: возможность передать событие - это кровеносная система архитектуры.
❓Что происходит при падении брокера?
🔸Продюсеры не могут отправлять сообщения. Бизнес замирает
Если продюсер не может опубликовать событие о завершении заказа, оплате или изменении данных, бизнес-процесс останавливается на самом старте.
Решение: outbox паттерн
Когда Продюсер публикует сообщение напрямую в брокер в рамках бизнес-транзакции - это считается плохим тоном. Вместо этого в рамках той же транзакции с БД, запись о событии сохраняется в специальную таблицу outbox в локальной базе данных сервиса. Это гарантирует атомарность: либо бизнес-данные и событие сохранены, либо нет. Отдельный, легковесный процесс забирает записи из outbox и отправляет их в брокер. Если брокер недоступен, процесс ждет и повторяет попытки с настроенной задержкой. Событие будет доставлено, когда это станет возможным.
В моей практике бывали случаи, когда эту outbox-таблицу приходилось разбирать руками, когда брокер больше 6 часов не мог забрать данные. Но это скорее исключение.
🔸 Консьюмеры перестают получать сообщения. Фоновые задачи умирают
Сервис-консьюмер, обрабатывающий уведомления или обновляющий кэши, становится бесполезным. Накопление очереди — это меньшее зло, чем полная остановка обработки.
Решение: Стратегия «Живучего консьюмера»
▪️Health Checks и Circuit Breaker: Консьюмер должен предоставлять строгий эндпоинт здоровья (/health), который проверяет не только его процесс, но и соединение с брокером и состояние потребления. Оркестратор (как правило, Кубер) должен рестартовать узел при проблемах.
▪️ Контрольные точки во внешнем хранилище: Не полагайтесь только на встроенный механизм коммитов брокера. Для критических задач периодически сохраняйте позицию обработки (ее еще называют смещением) в надежное, возможно, даже локальное дисковое хранилище. Это позволяет после сбоя начать не с последнего коммита в брокере (который мог быть потерян), а с известной безопасной точки.
▪️Изоляция обработки от потребления: Используйте паттерн «Конкурентный консьюмер» с внутренней очередью. Один поток читает из брокера и складывает сообщения во внутреннюю in-memory очередь (с лимитом), а пул рабочих потоков их обрабатывает. Падение брокера остановит только поток-читатель, а обработка текущих задач завершится.
...Асинхронность даёт новые формы отказов, а не избавляет от них.
Post #128
80