Модуль 4. Финал: квиз-баттл и защита проекта

Цель модуля: проверить себя по-настоящему. Финальный квиз на 50 вопросов по всем модулям (15 — в интерактивном блоке ниже, 35 — статичным разбором «вопрос → эталонный ответ»), затем — защита MVP «OrderFlow»: чек-лист код-ревью и типовые вопросы «почему выбрал X» с эталонами ответов.

Перед началом: Модули 1–3 этого курса; защита предполагает собранный MVP (Модуль 1). Формат: интерактивный квиз (15) + статичный разбор (35) = 50 вопросов. Трудоёмкость: ~4–6 ч (квиз 1 ч · доработка проекта 2–3 ч · защита 1 ч).

🏆 Часть 1. Интерактивный квиз-баттл (15 вопросов)

Вопросы собраны из всех секций финального баттла: Концепции (4), RabbitMQ (2), Kafka (3), NATS (2), Сравнение (2), Ситуационные (2). Остальные 35 — ниже, в статичном разборе.

🧩 Quiz "Проверь себя"

1. Quorum-очередь на 5 узлах. Сколько узлов может выйти из строя без потери доступности?
2. Kafka-консьюмер обрабатывает сообщение 40 секунд, max.poll.interval.ms=30. Цепочка событий?
3. Публикация с Nats-Msg-Id=X прошла, через 1 минуту — повтор с тем же Id при DuplicateWindow=2m. Результат?
4. Какие утверждения про транзакции Kafka верны? — выберите все подходящие
5. Идемпотентный обработчик помечает ключ как обработанный ДО бизнес-работы. В чём дефект?
6. У консьюмера JetStream AckExplicit, AckWait=30с, MaxDeliver=3. Сообщение трижды доставлено и трижды не ackнуто. Что дальше?
7. Какая модель обмена нужна для event sourcing с возможностью перечитать историю?
8. Pulsar shared subscription vs Kafka consumer group: ключевая разница?
9. Продюсер получил подтверждение записи, консьюмер обработал сообщение и упал до подтверждения брокеру. После рестарта сообщение придёт снова. Какая сквозная семантика получилась?
10. Outbox-диспетчер лежал 5 минут и при старте выхлестнул 100k событий разом. Консьюмеры идемпотентны. Что из этого следствие?
11. Consumer group из 5 инстансов читает топик с 3 партициями. После rebalance сколько инстансов получат работу?
12. SQS FIFO: что за ограничение throughput?
13. Продюсер с acks=all получил NOT_ENOUGH_REPLICAS. Что это значит?
14. Какие механизмы дают exactly-once бизнес-эффект между брокером и внешней БД? — выберите все подходящие
15. Consumer сделал nack(requeue=true) для постоянно падающего сообщения в RabbitMQ. Что произойдёт?

📚 Часть 2. Статичный разбор: 35 вопросов с эталонами

Так отвечайте на собеседовании — коротко, структурно, с ценой решения.

Секция A. Концепции и гарантии (в финале 10, здесь 6)

  1. Вопрос: Почему exactly-once невозможен «по сети» и что делают на практике? Эталон: Двухфазное подтверждение между независимыми системами не переживает все точки отказа (два генерала). Практика: at-least-once везде + идемпотентный эффектор: дедуп-ключ, транзакция «эффект + маркер применённости» в одной БД.

  2. Вопрос: Дайте определение backpressure и три слоя его реализации. Эталон: Механизм передачи «замедлись» вверх по потоку. Слои: pull/prefetch на клиенте; лимиты очередей (reject при переполнении); замедление источника (bounded-канал, 429, rate limit). Безлимитная очередь — не backpressure, а отложенный инцидент.

  3. Вопрос: Чем queue отличается от stream на уровне жизни сообщения? Эталон: В очереди сообщение удаляется по ack — перечитать нельзя. В стриме (логе) живёт по retention, консьюмеры двигают собственные оффсеты, история перечитываема. Отсюда replay, несколько проекций, аудит.

  4. Вопрос: Какие четыре метрики вы выведете на главный дашборд брокер-сервиса? Эталон: Consumer lag (тренд + возраст старейшего), DLQ rate, processing duration p99, in-flight/unacked. Плюс publish failure rate и confirm-латентность продюсера. Алерты — на тренды и SLO, не на абсолюты.

  5. Вопрос: idempotency-key: где рождается, где умирает, что если TTL истёк? Эталон: Рождается у источника операции (клиент/продюсер), едет в заголовках, умирает в дедуп-хранилище консьюмера. После TTL повтор не отличить от нового — TTL обязан покрывать худшее окно ретраев; для «вечной» дедупликации — бизнес-ключи (номер заказа), а не случайные UUID.

  6. Вопрос: Что такое poison pill и протокол выживания? Эталон: Сообщение, валющее обработчик. Протокол: безопасное декодирование (битое — сразу в DLQ), ограниченные ретраи с backoff+jitter, DLQ с алертом и процедурой разбора, сервис продолжает жить.

Секция B. RabbitMQ-глубина (в финале 8, здесь 6)

  1. Вопрос: Разница между basic.reject и basic.nack? Эталон: Семантика одинаковая (отказ с requeue-флагом); nack умеет multiple (подтвердить/отклонить пачку по delivery-tag), reject — только одиночное сообщение. На практике: nack для батчей, reject — редкий гость.

  2. Вопрос: Почему persistent-сообщение пропало после рестарта брокера? Эталон: Почти всегда очередь была nondurable: persistent-флаг работает только в паре с durable-очередью. Вторая причина — message ушёл в transient exchange... в RabbitMQ exchange'и не хранят сообщения, поэтому проверяйте и то, что публикация шла в нужный exchange с working binding.

  3. Вопрос: x-message-ttl vs per-message TTL: в чём подвох второго? Эталон: Очередной TTL — честный FIFO по времени. Per-message TTL проверяется с головы: короткий TTL за длинным не сработает вовремя. Для отложенных задач — очередь на интервал или delayed-message-exchange.

  4. Вопрос: Что видит продюсер при mandatory=true и отсутствии binding? Эталон: basic.return с сообщением (через NotifyReturn) и — в confirm-режиме — всё равно подтверждение: подтверждается приём, а не маршрутизация. Без mandatory сообщение исчезает молча.

  5. Вопрос: Quorum queue: что происходит при потере кворума и почему это «правильно»? Эталон: Очередь полностью недоступна (запись и чтение): группа 3/5 требует большинства. Это цена консистентности — брокер не выдаёт данные, которых не может подтвердить; алерт должен быть до потери кворума.

  6. Вопрос: Как построить в RabbitMQ «задача через 10 минут»? Эталон: Очередь-таймер delay.10m с x-message-ttl=600000 и DLX на рабочую очередь (или плагин delayed-message для произвольных задержек). Не per-message TTL в общей очереди — head-of-line блокировка.

Секция C. Kafka-глубина (в финале 10, здесь 7)

  1. Вопрос: Зачем ключ и что будет при его смене/отсутствии? Эталон: Ключ — детерминированный выбор партиции: порядок по сущности. Нет ключа — round-robin/sticky: порядок не гарантирован. Смена ключа события = разрыв порядка; добавление партиций ломает маппинг ключ→партиция.

  2. Вопрос: min.insync.replicas=2, acks=all: что получите при смерти двух реплик? Эталон: NOT_ENOUGH_REPLICAS на запись: брокер отказывается подтверждать без кворума ISR. Чтение работает. Это доступность, обменянная на долговечность — осознанный выбор для платежей, неправильный для телеметрии.

  3. Вопрос: Как работает идемпотентный продюсер и когда он бессилен? Эталон: PID + sequence per партиция; брокер отбрасывает повторы при ретраях. Бессилен: между сессиями продюсера (новый PID), между партициями, против дублей приложения (дважды вызвали send), для порядка между партициями.

  4. Вопрос: Что даёт transactional.id сверх идемпотентности? Эталон: Атомарные мультипартиционные записи + fencing: новый продюсер с тем же transactional.id поднимает эпоху, зомби не пишут. Полный consume-process-produce: offset-коммит в той же транзакции, read_committed у потребителей.

  5. Вопрос: Как устроен compacted topic и кто обязан уметь читать tombstone? Эталон: Хранится последнее значение по ключу; tombstone (value=nil) знаменует удаление и живёт delete.retention.ms. Компакт не мгновенен: консьюмер обязан брать последнее по ключу сам и трактовать tombstone как «удалить в проекции».

  6. Вопрос: Схема изменилась ломающим образом в BACKWARD-режиме — что случилось? Эталон: Registry отклонит регистрацию (или её подтвердят с failsafe-флагом, если понажимали кнопки). Консьюмеры начнут падать на декодировании. Правильно: трёхдеплойная миграция (писать оба поля → перевести читателей → убрать старое).

  7. Вопрос: Почему коммит оффсета после записи в БД, а не до? Эталон: До — при падении между commit и БД запись потеряна (at-most-once эффект). После — возможен повтор при падении между БД и commit: переживается идемпотентностью (applied_events/версия в транзакции). Потеря недопустима, дубль — ок.

Секция D. NATS — обзорный Модуль 4 «Фундамента» (в финале 7, здесь 5)

  1. Вопрос: Что произойдёт с publish в NATS Core без подписчиков? Эталон: Сообщение исчезнет без ошибок (или с ErrNoResponders в request-reply). Core не хранит: персистентность — только JetStream.

  2. Вопрос: DeliverPolicy для сценария «консьюмер подключился, увидеть всё с начала» vs «только новое»? Эталон: DeliverAll — вся история стрима; DeliverNew — только после подключения; DeliverLast — последнее сообщение; DeliverLastPerSubject — последнее по каждому subject'у (снимки состояния).

  3. Вопрос: Зачем MaxAckPending и что произойдёт при 0? Эталон: Это flow control: сколько сообщений может быть в «полёте» без ack. 0 = безлимит — брокер зальёт консьюмера на пике (аналог prefetch=0 в RabbitMQ).

  4. Вопрос: Как в JetStream сделать DLQ, если MaxDeliver не имеет DLQ из коробки? Эталон: Подписаться на system advisory $JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES и публиковать «пойманные» в отдельный DLQ-стрим (или обрабатывать в коде при nak/терм-логике). Аналог RabbitMQ DLX — собирается руками.

  5. Вопрос: KV-бакет: что внутри и три кейса применения? Эталон: Компактед JetStream-стрим с клиентским API (put/get/history/watch, CAS через revision). Кейсы: конфиги/feature flags с watch, service discovery, кэш-проекции для request-reply сервисов.

Секция E. Сравнение систем (в финале 8, здесь 6)

  1. Вопрос: Задача: фоновая конвертация файлов. Брокер? Эталон: Очередь задач: RabbitMQ (маршрутизация, per-message ack, приоритеты) или JetStream WorkQueue, или SQS — если без ops. Kafka избыточна: лог и consumer groups здесь лишняя сложность.

  2. Вопрос: Задача: действия пользователя как поток для аналитики и ML. Брокер? Эталон: Kafka (или Redpanda): retention, replay для новых потребителей, партиционирование по user_id, экосистема (Connect, коннекторы в озеро данных).

  3. Вопрос: Задача: realtime-пуш в UI + надёжный ресив команд. Брокер? Эталон: NATS: Core для push (суб-мс), JetStream для команд, request-reply для синхронных запросов — всё в одном брокере с одной библиотекой.

  4. Вопрос: RabbitMQ vs Kafka: почему семантики «ack» различаются так сильно? Эталон: RabbitMQ per-message: очередь удаляет подтверждённое, поэтому confirm/ack дёшевы и обязательны на каждое сообщение. Kafka per-batch: запись подтверждается по ISR, чтение — оффсетами в логе; ничего не удаляется, поэтому ack консьюмера — просто сдвиг позиции.

  5. Вопрос: Когда облако (SQS/PubSub) вместо самохоста — правильный ответ? Эталон: Нет ops-команды, объёмы в пределах лимитов, не нужен replay и тонкая маршрутизация, готовы платить за запросы и lock-in. Красные линии: FIFO-лимиты, цена на поллинг, отсутствие истории сообщений.

  6. Вопрос: Watermill: когда абстракция себя оправдывает и когда вредит? Эталон: Оправдывает: переносимость, in-memory-тесты, единые middleware, MVP с несколькими брокерами. Вредит: нужен специфичный контроль брокера (JetStream-ручки, транзакции Kafka), экстремальный throughput, тонкий тюнинг.

Секция F. Ситуационные задачи (в финале 7, здесь 5)

  1. Вопрос: Ночной инцидент: consumer lag вырос в 20 раз и не падает. Ваши действия по порядку? Эталон: 1) Проверить поток продюсеров (не всплеск ли). 2) Здоровье брокера (CPU/IO/партиции/ISR). 3) Здоровье консьюмеров (живы? обработка деградировала? upstream?). 4) Быстрая помощь: масштабировать консьюмеров (если есть запас партиций). 5) Разобрать корень по трейсам/метрикам, постмортем.

  2. Вопрос: В DLQ 50k сообщений. Что делать? Эталон: DLQ — процесс, не помойка: алерт должен был сработать раньше. Сгруппировать по причине (x-death/ошибки декодирования/баг релиза), баг-фикс → ретрай-реплей порциями с rate limit, битые — в архив с разбором. Настроить дашборд и процедуру, чтобы не повторилось.

  3. Вопрос: После релиза потребители получают каждый заказ дважды. Где искать? Эталон: 1) Продюсер: ретраи без идемпотентности/без Nats-Msg-Id/без дедуп-ключа. 2) Outbox-диспетчер: дубли при рестарте — ок по дизайну, значит дедуп на консьюмере не работает. 3) Консьюмер: сломанная идемпотентность (TTL меньше окна ретраев, не тот ключ). 4) Rebalance/K8s: restart loops посреди обработки.

  4. Вопрос: Требование бизнеса: «заказы в строгом порядке, миллион в час». Противоречие? Эталон: Млн/час ≈ 278/с — одна партиция потянет, глобальный порядок возможен, но хрупок (нет параллелизма). Скорее всего порядок нужен по account_id: партиционировать по ключу, ~278/с на ключ не бывает. Спросите «порядок чего для кого» — и почти всегда глобальность отпадает.

  5. Вопрос: P99 обработки 2 секунды при SLO 500 мс. Профиль показывает: обработка 30 мс. Куда смотрим? Эталон: Хвост вне обработчика: ожидание в очереди консьюмера (prefetch/skew: один воркер собирает всё), пул БД (wait), брокер (flush-паузы, репликация), GC/аллокации, TLS-handshake-шторм. Меряем отрезки по хопам (6.6/9.4), а не весь путь одним таймером.

🛡 Часть 3. Защита MVP «OrderFlow»

Чек-лист код-ревью перед защитой

Пройдите по списку из Модуля 1 и добавьте финальные пункты:

  • Каждый бизнес-эффект имеет дедуп-ключ и тест «дубль не меняет состояние».
  • Сбой-тесты: kill -9 посреди обработки, рестарт брокера, обрыв сети — инвариант «ноль потерь, дубли переживаются» в CI.
  • Трейс одного заказа виден в Jaeger end-to-end (скриншот в README).
  • Grafana-дашборд показывает инцидент, который вы устроили намеренно.
  • Load-отчёт: профиль rps → p50/p95/p99 → найденный bottleneck и его фикс.
  • README отвечает на «почему», а не только на «как»: решения и trade-offs.

Типовые вопросы защиты и эталонные ответы

«Почему Outbox, а не publish напрямую из ручки?» Эталон: атомарность с транзакцией заказа; прямой publish даёт два окна потери (до commit / после commit при упавшем publish). At-least-once наружу принимаем сознательно, консьюмеры идемпотентны.

«Почему Kafka для заказов, а RabbitMQ для команд Saga?» Эталон: событиям заказа нужен лог: retention, replay, несколько проекций, порядок по order_id. Командам Saga нужен per-message ack и DLX-цепочки ретраев — это семантика очереди. Выбор по семантике, а не по привычке.

«Почему NATS для уведомлений? Он же не хранит.» Эталон: два слоя: JetStream для надёжных уведомлений (стрим + дедуп по Nats-Msg-Id), Core — для огнегорящих push-статусов, где хранение не нужно и вредно. Latency и простота при точном выборе семантики.

«Что произойдёт, если упадёт Saga Orchestrator посреди процесса?» Эталон: состояние процесса персистентно (БД), команды идут через очередь с ack — при рестарте оркестратор продолжает с последнего шага; команды идемпотентны, поэтому повтор команды payment.refund безопасен.

«Где у вас exactly-once?» Эталон: нигде «по сети»; сквозной эффект — exactly-once по факту: at-least-once доставка + дедуп на каждом эффекторе (БД — applied_events, пуш — Nats-Msg-Id, письмо — дедуп-ключ). Могу показать тест, который убеждается в этом.

«Что сломается при 10x нагрузке?» Эталон: первым упрётся [найденный в S6 bottleneck — назовите свой]: план расширения — [партиции/воркеры/кэш]. Знаю точку, а не «поднимем ещё подов».

🎓 Итоги курса

За девять модулей вы прошли путь от «зачем нужен брокер» до защищённого MVP с тремя брокерами одновременно. Теперь вы можете:

  • Выбирать брокера по семантике задачи, а не по хайпу — и объяснять цену выбора.
  • Строить надёжные пайплайны: confirms, ack, prefetch, DLQ, идемпотентность.
  • Не бояться слов exactly-once — знать, где оно живёт и чем оплачивается.
  • Применять паттерны: Outbox, Saga, backpressure, circuit breaker.
  • Защищать, мониторить и масштабировать всё это: TLS/ACL, золотые метрики, бенчмарки, p99.

Что читать и смотреть дальше

  • Kafka: The Definitive Guide, 2nd ed. (Shapira et al.) — библия Kafka.
  • Designing Data-Intensive Applications (Kleppmann) — глава 11 «Streams»: фундамент, на котором стоит весь курс; глава 9 — консенсус и кворумы.
  • Enterprise Integration Patterns (Hohpe, Woolf) — каталог паттернов маршрутизации и интеграции, от которых выросли все брокеры.
  • Документация и блоги: rabbitmq.com (особенно разделы quorum queues и consumer ack), kafka.apache.org/documentation, docs.nats.io (JetStream).
  • microservices.io — каталог паттернов (Outbox, Saga, CQRS) с примерами.
  • Исходники Watermill и franz-go — образцовый Go-код вокруг брокеров.

Если Project «OrderFlow» дожил до финала — у вас есть работающий микросервисный стенд, которым можно гордиться в портфолио. До встречи в следующем курсе.