Messaging-паттерны на собеседовании системного аналитика
Зачем messaging на собесе SA
В микросервисной архитектуре сервисы общаются через сообщения чаще, чем через прямые HTTP-вызовы. Kafka, RabbitMQ, NATS — выбор зависит от паттерна. Системный аналитик должен понимать trade-offs и проектировать message flows.
На собесе системного аналитика messaging спрашивают через сценарии: «как организовать обмен между сервисами», «как сделать exactly-once delivery». Senior SA различает at-least-once vs exactly-once, понимает идемпотентность, dead-letter queues, partitioning.
Synchronous vs asynchronous
Sync (REST / gRPC):
- Client ждёт ответа
- Простой mental model
- Cascade failure: один upstream лёг → все downstream падают
Async (messaging):
- Publisher отправил → не ждёт
- Resilience: consumer может быть offline, message ждёт
- Eventual consistency
Когда async:
- Critical-path не нужен immediate response
- High throughput
- Loose coupling между сервисами
Подробнее — Микросервисы на собесе SA.
Message brokers
Apache Kafka:
- Distributed log, persistent storage
- High throughput (millions msg/sec)
- Partitioning для горизонтального масштабирования
- Consumers читают по offset
- Стандарт для event streaming, CDC, аналитики
RabbitMQ:
- Traditional message broker (AMQP)
- Queues + exchanges (routing)
- ACK-based delivery
- Хорош для job queues, RPC-style messaging
NATS / NATS JetStream:
- Lightweight, простой
- Pub-sub + persistence (JetStream)
- Низкая latency
Redis Pub/Sub / Streams:
- Для простых cases, fire-and-forget
- Streams — persistent log (Kafka-light)
Pub-sub vs queues
Pub-sub:
- Publisher → topic, многие subscribers получают каждое сообщение
- Kafka: consumer groups для load balancing внутри группы
- RabbitMQ: fanout exchange
Queue:
- Producer → queue, один consumer обрабатывает каждое
- RabbitMQ: классическая queue
- Используется для job processing, task distribution
В Kafka обе модели через consumer groups: один CG = queue (load balanced), несколько CG = pub-sub.
Delivery semantics
At-most-once:
- Message может теряться, но не дублироваться
- Fire-and-forget без ACK
- Применение: metrics, non-critical telemetry
At-least-once:
- Message может дублироваться, но не теряется
- Producer retry + consumer ACK
- Стандарт в Kafka, RabbitMQ
- Применение: большинство production scenarios
Exactly-once:
- Каждое message обработано ровно один раз
- Хитрая штука: full exactly-once невозможна в distributed system
- Достигается комбинацией at-least-once + идемпотентный consumer
- Kafka transactions + idempotent producer — близко к exactly-once в Kafka-only flows
Идемпотентность
Ключевая концепция для надёжного messaging.
Идемпотентный consumer: обработка дубликата = обработка оригинала. F(F(x)) = F(x).
Реализация:
- Идемпотентный ключ в message (idempotency-key, request-id)
- Consumer проверяет: «обрабатывал ли я уже этот ключ?»
- Storage для seen keys (Redis, DB table)
- TTL для очистки
Пример: payment service. Дублирующий message «charge $100» не должен списать $200. Идемпотентный ключ = order_id → проверка перед charge.
Outbox pattern
Атомарно сохранить data + опубликовать event — невозможно (DB + Kafka = две системы).
Решение:
- В одной DB-transaction: business data + event в
outboxтаблицу - CDC (Debezium) читает outbox → публикует в Kafka
- После публикации помечаем consumed
Гарантирует at-least-once delivery от source. Combined с идемпотентным consumer → exactly-once effect.
Подробнее — CDC и event sourcing на собесе DE.
Dead-letter queue (DLQ)
Когда consumer не может обработать message (poison message, bug, downstream сломан) — что делать?
Pattern:
- Retry N раз с exponential backoff
- Если не получается — message в DLQ
- DLQ читают вручную / отдельный consumer
- Alerts на DLQ growth
В Kafka DLQ — отдельный topic. В RabbitMQ — dead-letter exchange.
Partitioning в Kafka
Topic делится на partitions. Каждая — ordered log. Внутри partition order гарантирован, между — нет.
Partitioning key:
- Hash от ключа → partition
- Same key → same partition (order preserved)
- Пример:
user_id→ all events for user в одной partition
Зачем:
- Horizontal scaling: больше partitions → больше parallel consumers
- Per-key order: важно для events типа
user_updated(последний апдейт — финальный)
Анти-паттерн: один «hot» partition (большинство messages с одним ключом) → не масштабируется.
Backpressure
Producer пишет быстрее, чем consumer обрабатывает. Что делать?
Опции:
- Buffer broker (Kafka) — copes до retention; долгая обработка = lag
- Drop messages (acceptable для metrics)
- Throttle producer (rate limit)
- Scale consumers (auto-scaling)
В Kafka мониторят consumer lag (offset behind latest). Alert если > N → scale.
Типичные вопросы
«Kafka или RabbitMQ?»
Kafka: event streaming, high throughput, persistent log, аналитика. RabbitMQ: task queues, complex routing, RPC-style. Часто оба в одной компании.
«Как обеспечить exactly-once?»
At-least-once + идемпотентный consumer. Идемпотентный ключ в каждом message. Идемпотентность через unique constraint в БД или Redis-проверка.
«Что в DLQ?»
Messages, которые consumer не смог обработать после retries. Причины: bad payload, downstream service down, bug. Action: alert + manual review + fix + reprocess.
«Как организовать обмен заказа между сервисами?»
Order Service → Kafka topic orders.created. Consumers: Inventory (резерв), Payment (charge), Notifications (email), Analytics (BI). Outbox + идемпотентность.
Частые ошибки
- Sync везде. «Микросервис вызывает микросервис через REST» → cascade failure
- Без идемпотентности. At-least-once → дубликаты обработаны → BUG в проде
- Без DLQ. Poison message → consumer лупится → topic stuck
- Hot partition. Все messages с одним ключом → один consumer перегружен
- JWT в Kafka message. Sensitive data в plain log — security violation
FAQ
Persistent vs ephemeral messages?
Persistent (Kafka, RabbitMQ durable queue): данные на диске, выживает restart. Ephemeral (Redis Pub/Sub, NATS Core): in-memory, теряется при failure. Production обычно persistent.
Какой retention для Kafka?
Зависит от use case: events для аналитики — 7-30 дней; CDC — может быть compacted (keep last value per key); audit log — годы.
Schema registry нужен?
Для production Kafka — да. Schema evolution без коссистентности → ломаются consumers. Confluent / Apicurio.
Consumer group rebalancing — что это?
Когда consumer присоединяется / отваливается, partitions перераспределяются между members. Stop-the-world pause. Cooperative rebalancing (KIP-429) — incremental.
Kafka Streams или Flink?
Streams — embedded library, простой stateful processing. Flink — полноценный stream-processing framework, exactly-once, windowing. Streams для simple, Flink для complex.