В микросервисах половина работы происходит не в ответе на запрос, а позже: сервис публикует событие, другие его читают. Тестировщику нужно уметь найти сообщение, понять, почему оно не обработалось, и найти следы запроса в логах.
Зачем очереди
Сервис заказов после оплаты публикует событие order.paid. Склад и сервис писем читают его сами. Выигрыш: заказ не ждёт склад, а если склад лежит, сообщения подождут в брокере. Цена: всё становится асинхронным, и «ответ 200» больше не значит «всё сделано».
Kafka для тестировщика
- Топик: поток сообщений одного вида, например
orders. - Партиция: часть топика. Порядок гарантирован только внутри партиции. Сообщения с одинаковым ключом (id заказа) попадают в одну партицию, поэтому события одного заказа приходят по порядку.
- Offset: позиция сообщения в партиции.
- Consumer group: потребители одной группы делят партиции, каждое сообщение обрабатывает один из них. Разные группы читают топик независимо и получают всё.
- Retention: сообщения не удаляются после чтения, а живут заданное время.
- Consumer lag: насколько потребитель отстал. Растущий lag значит, что обработка не успевает или встала.
Смотрят сообщения через Kafka UI (есть несколько открытых веб-интерфейсов) или консольный потребитель kafka-console-consumer.
RabbitMQ кратко
Отправитель пишет в exchange, а тот раскладывает по очередям по правилам: direct (точный ключ), topic (шаблоны order.*), fanout (во все привязанные очереди), headers. Потребитель подтверждает обработку (ack). «Сообщение пропало» часто значит, что очередь не привязана к exchange.
Гарантии доставки
- At most once: не больше раза, возможны потери.
- At least once: хотя бы раз, возможны дубли. Самый частый режим.
- Exactly once: ровно раз, только в ограниченных условиях.
Практический вывод: потребитель должен быть идемпотентным. Если сервис начислил бонусы и упал до подтверждения, после рестарта он получит сообщение снова. Тест: отправить одно сообщение дважды, эффект должен быть один.
DLQ
Сообщение с битым форматом падает при каждой попытке. Его уводят в dead letter queue: остальные обрабатываются, а проблемное ждёт разбора, срабатывает алерт.
Outbox
Записать заказ в базу и отправить событие в брокер это две системы, и между ними сервис может упасть. Паттерн transactional outbox: событие пишется в таблицу outbox в той же транзакции, что и заказ, а отдельный процесс отправляет его в брокер и отмечает sent_at. Для тестировщика это подарок: SQL-запросом видно, какие события не ушли, какие задвоились и для каких заказов события нет вообще.
Что тестировать
- Корректное сообщение обработано, эффект есть.
- Дубль не даёт двойного эффекта.
- Невалидное сообщение в DLQ, потребитель живёт дальше.
- Потребитель лежал, поднялся и догнал без потерь.
- События одного заказа пришли не в том порядке.
- Новая версия схемы сообщения не ломает старого потребителя.
В автотестах асинхронный результат ждут опросом с таймаутом (например Awaitility в Java), а не sleep.
Логи
Уровни: TRACE, DEBUG, INFO, WARN, ERROR (иногда FATAL). Ошибка, записанная как INFO, не попадёт в алерты: это тоже баг.
Trace id. На входе запрос получает идентификатор, он передаётся между сервисами (стандарт W3C Trace Context, заголовок traceparent) и пишется в каждую строку лога. Тогда в Kibana или Grafana Loki все шаги запроса через пять сервисов находятся одним поиском, а в Jaeger видна цепочка вызовов с длительностями.
Где смотреть: Kibana поверх Elasticsearch или OpenSearch, Grafana Loki, Sentry для ошибок. На стенде docker logs -f, kubectl logs -f, на сервере tail -f и grep.
Что искать в самих логах: пароли, токены, номера карт и лишние персональные данные. Это утечка и нарушение PCI DSS и 152-ФЗ.
Что спросят на собесе
- Зачем нужны брокеры сообщений и чем Kafka отличается от RabbitMQ?
- Что такое партиция и consumer group?
- Что значит «at least once» и как с этим жить?
- Как вы тестировали асинхронную интеграцию?
- Как найти причину ошибки в микросервисах?