Синхронный вызов: «позвонил и ждёшь ответа». Асинхронный: «отправил сообщение и занимаешься своим делом». Асинхронность развязывает системы во времени: получатель может лежать, а сообщение дождётся его в брокере.
Когда асинхронно
- Отправителю не нужен немедленный результат (письмо, начисление бонусов, аналитика).
- Событие нужно нескольким потребителям (заказ создан: склад, CRM, аналитика).
- Нужно сгладить пики нагрузки: очередь накопит, обработчики разгребут.
- Долгие операции (генерация отчёта, распознавание документа).
Минусы: сложнее отлаживать, появляется eventual consistency (данные согласуются не сразу), нужно думать о дублях и порядке.
Очередь и топик
- Очередь (point-to-point): каждое сообщение получает один потребитель. Задачи на обработку.
- Публикация-подписка (pub/sub): каждое сообщение получают все подписчики. События.
RabbitMQ и Kafka
| RabbitMQ | Kafka | |
|---|---|---|
| Модель | брокер очередей: exchange → очереди | распределённый журнал: топики из партиций |
| После прочтения | сообщение удаляется после подтверждения | хранится заданное время, можно перечитать |
| Маршрутизация | гибкая: direct, topic, fanout, headers | по ключу в партицию |
| Порядок | в пределах очереди | в пределах партиции |
| Сильная сторона | задачи, сложная маршрутизация, RPC поверх очередей | поток событий, высокая пропускная способность, перечитка, event sourcing |
В Kafka потребители объединяются в consumer group: партиции делятся между участниками группы, каждая группа читает весь топик независимо. Сообщения с одинаковым ключом (например, order_id) попадают в одну партицию и читаются по порядку.
Гарантии доставки
- At most once: не больше одного раза, возможна потеря.
- At least once: не меньше одного раза, возможны дубли. Самый частый выбор.
- Exactly once: ровно один раз. На практике достигается как «at least once + идемпотентный потребитель» или транзакциями внутри одной платформы (Kafka transactions).
Отсюда главное правило: потребитель идемпотентен. Храним id обработанных сообщений или делаем операцию такой, что повтор ничего не меняет (UPSERT, проверка статуса).
Проблема двойной записи и outbox
Сервис должен сохранить заказ в БД и отправить событие в брокер. Если сделать это двумя операциями, одна может упасть: заказ есть, события нет (или наоборот).
Transactional outbox: в той же транзакции, что и заказ, пишем событие в таблицу outbox. Отдельный процесс (поллер или CDC, например Debezium) читает outbox и публикует в брокер. Доставка at least once, значит потребитель идемпотентен.
Саги
Распределённая операция из шагов в разных сервисах без общей транзакции. Если шаг упал, выполняют компенсирующие действия: отменить резерв, вернуть деньги.
- Хореография: сервисы реагируют на события друг друга. Просто на 2-3 шагах, дальше трудно понять, кто что делает.
- Оркестрация: центральный оркестратор говорит, что делать дальше. Нагляднее, легче менять, но оркестратор становится важной точкой.
Ошибки и DLQ
Сообщение, которое не удаётся обработать (битый формат, бизнес-ошибка), не должно бесконечно возвращаться в очередь. После N попыток с задержкой его перекладывают в DLQ (dead letter queue), где разбирают вручную или отдельным процессом.
Контракт сообщения
Аналитик описывает: имя события в прошедшем времени (OrderCreated), версию схемы, ключ, обязательные поля, кто публикует, кто потребляет, гарантии, порядок, что делать с дублями. Для описания есть AsyncAPI, схемы хранят в Schema Registry (Avro, Protobuf, JSON Schema).
Два стиля событий:
- Event notification: «заказ 42 изменился», за деталями потребитель идёт в API.
- Event-carried state transfer: в событии все нужные данные, потребитель не ходит обратно.
Частые ошибки
- Ждать ответа через брокер как через синхронный вызов, не продумав таймаут.
- Не учесть дубли и порядок.
- Отправлять событие до коммита транзакции.
- Нет DLQ и мониторинга отставания потребителей (lag).
Что спросят на собесе
- Когда выберешь асинхронную интеграцию вместо REST?
- Чем Kafka отличается от RabbitMQ?
- Какие гарантии доставки бывают? Как бороться с дублями?
- Что такое transactional outbox?
- Что такое сага, чем хореография отличается от оркестрации?