
Привет, Хабр! На связи Александр Усачёв, системный аналитик в группе облачных продуктов Рунити. В основе нашей облачной платформы Рег.облако лежит микросервисная архитектура: каждый сервис отвечает за свой участок бизнес-логики — от биллинга до управления сетями. Между собой они обмениваются задачами через брокер сообщений.
В этой статье расскажу, как мы повысили отказоустойчивость нашей облачной платформы — и почему выбрали асинхронные цепочки задач вместо синхронных вызовов. Это история про устойчивость, Celery, RabbitMQ и немного про то, как инженерам стало жить спокойнее.
Навигация по тексту:
В микросервисных платформах синхронные вызовы часто становятся «слабым звеном». Один зависший шаг блокирует исходный запрос, загружает потоки обработки, тормозит другие операции и провоцирует каскадные сбои. В облачных сценариях это критично: сервисов много, нагрузка высокая, уровень SLA важен.
Чтобы снять эти риски, облачная платформа изначально спроектирована на асинхронных цепочках задач. Это повышает отказоустойчивость: пользователи в подавляющем большинстве случаев получают успешный результат, даже если выполнение занимает больше времени.
Синхронная модель: почему она не подходит для бизнес-операций
Синхронные запросы остались только на первом шаге — при обращении пользователя к API. Дальше такая модель быстро упирается в ограничения.
Типовая бизнес-операция, например заказ виртуального сервера, включает 8–15 последовательных обращений к разным подсистемам: биллингу, OpenStack и другим. Ошибка на любом промежуточном шаге приводит к сбою всей операции — и повторить ее корректно в рамках одного синхронного запроса уже нельзя.
Долгие действия — вроде создания сервера из снапшота объемом более 100 ГБ — могут длиться от нескольких минут до часов. Они не укладываются в стандартные таймауты и снижают надежность. Если один из сервисов отвечает медленно, исходный запрос блокируется в ожидании. Рабочие потоки простаивают, очередь растет, деградация накапливается и затрагивает других пользователей.
Мы пришли к выводу, что для пользовательских операций нужна развязка по времени и управляемое выполнение шагов — то есть асинхронная схема.
Асинхронные цепочки задач: в чем затея и как это работает
Каждый пользовательский запрос превращается в цепочку задач. Они передаются через брокер сообщений и выполняются нужными сервисами. Для каждой задачи сохраняются статус и параметры запуска: видно, какие шаги завершились, где возникла ошибка, можно перезапустить отдельный шаг или всю цепочку.
Ключевой механизм — отложенные задачи. Если сервис A инициирует выполнение цепочки в сервисе B, он не ждет прямого HTTP-ответа. Задача в A завершается только после того, как через брокер приходит уведомление о завершении цепочки в B. Такой подход особенно пригодился при нашем переходе IaaS-части на OpenStack.
Практический эффект — ошибки и повторы обрабатываются внутри цепочки и не доходят до пользователя. В 99 % случаев он получает успешный результат, пусть и с небольшой задержкой.
Цена — большее время выполнения и дополнительные ресурсы. Это наш осознанный компромисс в пользу отказоустойчивости.
Как мы пришли к текущей архитектуре
Асинхронность заложили еще на этапе проектирования. Первый вариант очереди задач работал на базе данных: отдельная таблица использовалась как очередь, а обработчик был собственный. Со временем, с ростом числа операций и длины цепочек, поддерживать такую схему стало неудобно.
Мы перешли на Celery — готовую библиотеку фоновых задач, которая унифицировала подход между сервисами, и RabbitMQ как брокер сообщений. Поверх Celery добавили собственную обвязку для повышения надежности и управляемого перезапуска упавших цепочек.
Паттерны распределенных транзакций вроде Saga или Outbox не применяли: в нашем домене важна гарантированная последовательность выполнения задач, а не координация транзакций между сервисами.
Кейс: как именно асинхронность повышает устойчивость
Теперь давайте рассмотрим это на реальном примере.
Проблема: Создание ресурса в облаке задействует несколько сервисов. В синхронной схеме это приводит к блокировкам, росту очередей и риску каскадных сбоев. Долгие операции часто выходят за таймауты.
Решение: Пользовательский запрос превращается в цепочку асинхронных задач. Поддерживаются отложенные шаги: если нужно запустить отдельную цепочку в другом сервисе, текущая задача продолжится только после уведомления брокера о ее завершении.

Раньше: сервис ждал ответ от каждого шага в цепочке → дополнительная нагрузка и блокировки.
Сейчас: сервис уведомляет брокер о завершении шага → нагрузка ниже, устойчивость выше.

Внутреннее устройство внешнего сервиса нам недоступно, но ответы возвращаются по установленному протоколу, и цепочка продолжается.
Какой эффект от этого мы получаем:
Пользовательские операции не теряются: даже при длительном выполнении другие запросы продолжают обслуживаться.
Ошибки обрабатываются на уровне шагов цепочки; их можно повторять адресно.
Дежурные инженеры могут перезапускать конкретные шаги или всю цепочку через админку — без отката остальных операций.
В результате в 99 % случаев пользователь получает успешный итоговый ответ.
Наглядный пример — кейс устойчивости
В 2022 году в одном из наших дата-центров с IaaS-инфраструктурой произошел четырехчасовой простой. Заказы новых услуг и операции по действующим не потерялись: цепочки сохранились и после восстановления связности автоматически перезапустились.
В синхронной модели такой сценарий привел бы к частичной утрате операций.
Вывод: ограничения и компромиссы
Время выполнения: «Длинные» операции, например развертывание из крупного снапшота, занимают больше времени.
Блокировка ресурсов: На период выполнения цепочки соответствующий ресурс остается заблокированным и недоступным для параллельных действий.
Нагрузка: Ранее высокая нагрузка из-за ожидания ответа на каждом шаге снизилась после перехода на модель с уведомлениями брокера и поддержкой отложенных задач.
Путь запроса: что происходит «под капотом»
Теперь давайте для наглядности зафиксируем стандартный маршрут:
Пользователь отправляет запрос.
Запрос попадает в пользовательское API и далее — в GraphQL-сервер, где формируется набор нужных обращений.
Бизнес-сервис формирует цепочку задач и публикует ее в RabbitMQ.
Обработчики задач Celery последовательно выполняют задачи, взаимодействуют с другими сервисами и фиксируют статусы.
При необходимости инициируется цепочка в другом сервисе; текущий шаг окончится после уведомления брокера о ее завершении.
По итогам цепочки пользователю возвращается результат.

Инструменты и мониторинг: от прозрачности к метрикам
Асинхронная архитектура не должна превращаться в «черный ящик». Мы начали с прозрачности выполнения, затем добавили метрики и операционные витрины. Как это выглядит сейчас?
Админка цепочек
Интерфейс состоит из двух экранов. На первом отображается хронологический список активных и упавших цепочек (новые — сверху).

На втором — детальная карточка: состав задач, текущее состояние каждого шага, параметры запуска и результаты выполнения.

В карточке видно ID, параметры, статусы и даты выполнения задач; доступны действия — перезапуск или завершение цепочки.

Это позволяет инженерам оперативно восстанавливать выполнение без обращения к логам или вмешательства в код.
Метрики и наблюдаемость
В Prometheus собираются технические метрики по воркерам Celery — CPU, память, сеть — и по очередям RabbitMQ. Эти данные служат ранними индикаторами перегрузки. Для визуализации используется общий дашборд в Grafana, где отображаются показатели по контейнерам и очередям.
Пороговые значения по глубине очередей и ресурсам воркеров пока не заданы: дашборды применяются для наблюдения и анализа, без автоматического алертинга. Правила эскалации и интеграция с системой инцидентов тоже не внедрены — дежурные инженеры следят за состоянием через админку и при необходимости перезапускают цепочки вручную.
В продакшене работает от двух до шести контейнеров Celery, в зависимости от сервиса. RabbitMQ остается основным брокером: его стабильность и поддержка в текущей версии Celery полностью покрывают наши потребности, поэтому переход на Kafka мы не планируем.
Архитектура на этом этапе считается завершенной: ключевые функции реализованы, а дальнейшие изменения направлены на удобство эксплуатации и мониторинг.
Вместо заключения
Для Рег.облака асинхронные цепочки задач стали основой стабильности. Мы прошли путь от очередей в базе данных до Celery и RabbitMQ — и видим, что эти усилия были оправданы.
Если вы решали похожие задачи или нашли другой способ повысить отказоустойчивость — расскажите в комментариях. Всегда интересно сравнить подходы и обменяться опытом!