Модуль 4. RabbitMQ Streams и multi-DC: shovel, federation и когда это вместо Kafka
Цель модуля: закрыть курс инженерной надстройкой над AMQP: RabbitMQ Streams — лог-модель с replay и офсетами внутри RabbitMQ; shovel и federation — связь кластеров; и честное решение «Streams или Kafka».
Перед началом: Модули 1–3, курс «Фундамент» (модели доставки), знакомство с Kafka из её курса — для сравнения. Трудоёмкость: ~8–10 ч (теория 4 ч · практика 4 ч · квиз 1 ч).
📖 4.1. RabbitMQ Streams: лог внутри Rabbit
Обычная очередь удаляет сообщение после ack — «до ack» и точка. Stream — это append-only лог: сообщения лежат на диске до retention (по времени/размеру), потребители читают с офсетом и могут перечитать сколько угодно раз, несколько независимых читателей не конкурируют за сообщения:
bashrabbitmqadmin declare queue name=orders kind=stream \ arguments='{"x-stream-max-length-bytes": 5000000000, "x-stream-max-segment-size-bytes": 500000000}'
| classic/quorum | stream | |
|---|---|---|
| Жизнь сообщения | до ack | до retention (дни, если нужно) |
| Повторное чтение | нет | да, с любого офсета |
| Порядок | FIFO, но конкуренция за голову | строгий, как Kafka |
| Консьюмеры | конкурентные (сообщение уходит одному) | независимые группы с офсетами |
| Throughput | сотни тысяч msg/s | миллионы msg/s на узел (протокол оптимизирован) |
Ключевое отличие от Kafka: нет партиций — stream живёт на кластере
целиком (реплики), порядок глобальный в стриме, масштабирование —
шардированием стримов руками (как в Redis, Модуль 5 курса Redis).
Протокол — отдельный (порт 5552, плагин rabbitmq_stream),
клиент — rstream-go; записывать можно и по AMQP 0-9-1 — в стрим
это обычная публикация.
Когда stream, а не очередь: нужны replay/аудит/догон новых потребителей, несколько независимых читателей одного потока, retention задолго за пределы обработки — и при этом уже стоит RabbitMQ.
📖 4.2. Чтение с офсетом и группы
Stream-потребитель подписывается с указанием точки входа:
first— с самого начала (replay!);last— только новое;offset— конкретный офсет / timestamp («всё с 14:00»);- consumer group: несколько читателей делят офсет-коммит группы (как consumer group Kafka) — для масштабирования обработки.
go// rstream-go (эскиз) env := rabbitstream.NewEnvironment(...) offset := rabbitstream.NewOffsetType(rabbitstream.OffsetFirst) // replay reader, _ := env.NewConsumer("orders", handler, rabbitstream.ConsumerOffset(offset), rabbitstream.ConsumerName("billing"))
Подтверждение — офсет-коммит группы: тоже at-least-once, идемпотентный обработчик из «Фундамента» снова в деле. Клиент держит heartbeat и переподключение — как всегда, «живость» решает consumer_timeout.
📖 4.3. Shovel: перекачка между брокерами
Shovel — встроенный переносчик: читает из одной очереди/стрима (свой брокер, vhost, очередь) и публикует в другой, с подтверждениями на обоих концах. Конфигурируется динамически (parameters):
bashrabbitmqctl set_parameter shovel orders-drain \ '{"src-uri":"amqp://src","src-queue":"orders", \ "dest-uri":"amqp://dest","dest-queue":"orders", \ "ack-mode":"on-confirm","prefetch-count":100}'
Применения: миграция кластеров без остановки (dual-write через shovel),
Active-Passive DR (стендайби догоняется постоянно), перенос истории из
legacy. Semantics: ack-mode=on-confirm — at-least-once на обоих
концах; идемпотентность получателя — ваша (снова «Фундамент»).
📖 4.4. Federation: гео и развязка кластеров
Federation — постоянная связь exchange↔exchange или queue↔queue между разными кластерами через AMQP-линки: upstream тянет сообщения к локальному exchange как обычный клиент. Отличия от shovel:
| Shovel | Federation | |
|---|---|---|
| Тип связи | точка-точка, перенос | долгоживущие линки, подписка |
| Топология | гибкая, параметризуемая | декларативная (upstream-наборы) |
| Классика применения | миграция, DR | Active-Active, гео-агрегация |
Federation не реплицирует гарантии кластера: это at-least-once поверх AMQP между независимыми брокерами (у каждого свои очереди, своя глубина). Для денег и строгих гарантий — cross-DC Kafka (или отдельная архитектура), federation — для развязки доменов и сбора событий из регионов.
📖 4.5. Multi-DC шаблон выбора
- Active-Active (federation): оба ДЦ живут, события текут в обе стороны; очереди независимы; дубли — норма, идемпотентность обязательна;
- Active-Passive (shovel/репликация на стендайби): один ДЦ пишет, второй догоняется; failover — ручной/полуавтоматический, RPO зависит от задержки shovel;
- Ничего из этого: если нужен один лог с сильными гарантиями по ДЦ — это отдельный разговор (Kafka MirrorMaker / BookKeeper-класс решений), а не RabbitMQ-надстройки.
📖 4.6. Streams RabbitMQ vs Kafka: короткое решение
Берите RabbitMQ Streams, если: RabbitMQ уже стоит, объёмы до сотен тысяч msg/s, нужна replay-история на дни, topology/маршрутизация AMQP рядом, и не хочется ещё одного кластера в эксплуатации. Берите Kafka, если: retention на недели/месяцы, партиции и масштабирование записи, экосистема (Connect/Streams), жёсткие throughput-требования, много независимых consumer-групп на один лог. Формулировка для ревью: «Streams — лог внутри RabbitMQ; Kafka — лог, вокруг которого построена инфраструктура».
💻 Практика
- Включите Streams:
make up-streams(плагин + порт 5552); создайте streamordersс retention 1 ГБ. - Запись и replay: продюсер AMQP пишет 1 000 событий; два
независимых читателя rstream-go читают
first— оба получают все 1 000 (вот оно, непривычное для AMQP); перезапуск читателя сoffset=last— только новые. - Группа: два читателя в одной группе — офсет общий, работа делится; остановите одного, второй доезжает.
- Shovel (демо-миграция): создайте
orders(queue) иorders-v2(stream); shovel перекачивает очередь в стрим; гоняйте трафик и убедитесь в сохранности по счётчику ID. - Federation (скетч): два стенд-кластера (docker network),
exchange-federation
eventsиз A в B; напишите в A — прочитайте в B; отключите A — B продолжает жить (независимость кластеров).
Артефакт: скрипты двух читателей (replay + группа), конфиг shovel, скриншот «оба читателя получили все сообщения» — приклад к ADR «streams vs kafka» из курса Redis (М6).
🧩 Quiz "Проверь себя"
✅ Итоги модуля
| Тема | Главное |
|---|---|
| Streams | Лог внутри Rabbit: retention, replay, офсеты, группы; нет партиций |
| Клиент | rstream-go, порт 5552; запись можно по AMQP |
| Shovel | Перенос между брокерами, at-least-once, миграции и DR |
| Federation | Линки между кластерами: Active-Active, гео, независимость |
| Решение | «Streams — лог внутри Rabbit; Kafka — лог со инфраструктурой вокруг» |
🎓 Куда дальше
Курс RabbitMQ закрыт по тройке «модель → мониторинг → инциденты» плюс надстройка Streams/multi-DC. Осталось в треке: капстоун OrderFlow — там Streams одного из брокеров, shovel-миграция между спринтами и все инцидент-навыки трека соберутся в один проект.