Ответ
Асинхронная коммуникация через шины (RabbitMQ, Kafka, AWS SQS) решает многие задачи масштабирования, но имеет ряд существенных недостатков:
- Сложность отладки и мониторинга. Трудно отследить полный путь сообщения (distributed tracing). Нет синхронного ответа об ошибке, проблемы могут проявиться с задержкой в другом сервисе.
- Нарушение порядка сообщений. В системах с несколькими консьюмерами или партициями (Kafka) нет гарантии, что сообщения
Событие A→Событие Bбудут обработаны в том же порядке. Это требует идемпотентности или специальной логики. - Потенциальное дублирование обработки. Из-за retry-механизмов, таймаутов или сбоев консьюмера одно и то же сообщение может быть обработано несколько раз.
- Задержки (latency). Не подходит для сценариев, требующих немедленного ответа пользователю (синхронный HTTP-запрос).
- Усложнение архитектуры и кода. Появляются новые сущности: очереди, обменники, dead-letter queues. Код должен обрабатывать повторные попытки, идемпотентность, компенсирующие транзакции (Saga pattern).
Пример проблемы с порядком:
// Сервис заказов публикует события
$messageBus->dispatch(new OrderCreated($orderId)); // Событие 1
$messageBus->dispatch(new OrderPaid($orderId)); // Событие 2
// Сервис доставки может получить их в порядке: 2, 1
// и попытаться начать доставку несуществующего заказа.
Для борьбы с этим в Kafka можно использовать ключ партиционирования (например, orderId), чтобы события одного заказа попадали в одну партицию и сохраняли порядок.
Ответ 18+ 🔞
Да ты посмотри, какая красота! Асинхронщина через всякие RabbitMQ да Kafka — это ж святое дело для масштабирования, все архитекторы только об этом и говорят. Но, блядь, как же там подводных камней-то овердохуища! Прям я д р ё н а в о ш ь!
Вот смотри, берёшь ты эту свою шину, радостный такой, а там:
- Отладка и мониторинг — пиздец. Попробуй проследить, где конкретно сообщение накрылось медным тазом. Оно ушло в трубу, а ошибка вылезет через час в другом сервисе, который даже не в курсе, откуда ноги растут. Доверия ебать ноль, что всё пройдёт гладко.
- Порядок сообщений — хуй с горы. Обещали FIFO? Ага, щас. В той же Kafka, если консьюмеров несколько или партиций, то событие
Бможет прилететь раньше событияА. И твой сервис доставки будет, как мартышлюшка, пытаться отвезти заказ, который ещё даже не создали. Удивление пиздец у него на лице будет. - Дубли — их дохуя. Механизмы повторов, таймауты — всё это приводит к тому, что одно и то же сообщение могут обработать несколько раз. Пиши идемпотентность, дружок, без неё — пидарас шерстяной.
- Задержки. Ждать ответа тут бесполезно. Если юзеру надо сразу — это не твой вариант. Тут терпения ноль ебать.
- Архитектура усложняется до ёперного театра. Очереди, DLQ, компенсирующие транзакции... Код превращается в пиздопроебибну логику обработки краёв, а не бизнес-процессов.
Вот тебе живой пример, как порядок хуй с винтом:
// Сервис заказов публикует события
$messageBus->dispatch(new OrderCreated($orderId)); // Событие 1
$messageBus->dispatch(new OrderPaid($orderId)); // Событие 2
// Сервис доставки может получить их в порядке: 2, 1
// и попытаться начать доставку несуществующего заказа.
Представляешь? Прилетает «Оплачено», а «Создан» ещё где-то в пути. Сервис доставки сам от себя охуел. В Kafka, чтобы такого не было, надо юзать ключ партиционирования (тот же orderId), чтобы все события по одному заказу шли в одну партицию и порядок не теряли. Но это уже хитрая жопа, за которой надо следить.
Короче, инструмент мощный, но вы ходите по охуенно тонкому льду. Один неверный шаг — и будет вам хиросима и нигерсраки в продакшене.