Транспорт бэкенда
Redis Streams и Pub/Sub
В 2018 году Antirez добавил Streams в Redis и написал: 'Я хотел сделать что-то вроде Kafka, но такое, чтобы могло жить внутри Redis.' Получилось не Kafka - но для 80% задач, где Kafka избыточна, Redis Streams стал правильным выбором.
- BullMQ - самая популярная job queue для Node.js - использует Redis для хранения задач, а в новых версиях поддерживает Streams как backend
- Instagram использует Redis для activity feed fan-out: публикация поста - событие в Stream, воркеры раскидывают в ленты 300+ миллионов подписчиков
- Cloudflare использует Redis Streams для edge-событий: rate limiting, firewall events, analytics pipeline
Redis Pub/Sub: ephemeral messaging
Redis Pub/Sub существует с 2010 года. Это простейший fire-and-forget: PUBLISH отправляет сообщение всем активным подписчикам канала. Нет персистентности, нет буферизации, нет ACK. Если подписчик offline - сообщение теряется безвозвратно.
Pub/Sub в Redis работает через отдельный connection - подписанный клиент не может выполнять другие команды. Redis хранит список подписчиков в памяти. Один PUBLISH - O(N) отправок, где N - количество подписчиков. При 10 000 подписчиков на один канал это становится узким местом.
Когда Pub/Sub достаточно: real-time уведомления в браузер через WebSocket (BullMQ использует именно его), chat-сообщения при условии что потеря допустима, invalidation кешей в multi-node окружении. Когда не достаточно - нужны Streams.
Что происходит с сообщением Pub/Sub если подписчик offline?
Redis Streams: append-only log в памяти
Redis Streams появились в 2018 году (Redis 5.0). Antirez (Salvatore Sanfilippo) открыто говорил: цель - что-то вроде Kafka, но в Redis. Streams - это append-only log с ID-адресацией и встроенной поддержкой consumer groups.
Каждое сообщение в Stream имеет уникальный ID формата `milliseconds-sequence`. `XADD` с ID `*` автогенерирует монотонно возрастающий ID. Это гарантирует ordering - важное свойство для event log.
Stream хранится в памяти в радикс-дереве (radix tree) - эффективная структура для range queries по ID. `XRANGE orders from to` работает за O(log N + M). Данные можно сохранять на диск через RDB/AOF как обычные Redis-данные. `MAXLEN` с тильдой (`~`) - приблизительная обрезка, быстрее точной.
Redis Streams - не замена Kafka по throughput. Redis однопоточный по командам (хотя I/O многопоточный с Redis 6). Kafka партицированный и горизонтально масштабируемый. Redis Streams - для умеренных нагрузок, где Redis уже в стеке.
Что гарантирует монотонно возрастающий ID в Redis Streams?
Consumer Groups: distributed processing
Consumer Groups в Redis Streams - прямой аналог Kafka Consumer Groups. Группа потребителей делит Stream: каждое сообщение доставляется ровно одному consumer из группы. Разные группы читают независимо - каждая видит все сообщения.
Pending Entries List (PEL) - ключевая концепция. Redis хранит все доставленные но не подтверждённые сообщения в PEL. Если consumer упал - его pending-сообщения можно перелокировать через `XCLAIM`. Это и есть at-least-once гарантия в Redis Streams.
BullMQ - популярная job queue библиотека для Node.js - построена на Redis. Использует комбинацию List (для очереди) и Hash (для данных задач). В BullMQ v4+ есть поддержка Streams как альтернативный backend.
Для чего нужен XACK в Consumer Groups?
Redis Streams vs Kafka: прагматичный выбор
Redis уже есть в 80% production-стеков - для кеширования, сессий, rate limiting. Redis Streams - это messaging без дополнительного инструмента. Kafka - отдельная инфраструктура с JVM, ZooKeeper или KRaft, операционным overhead.
Redis Streams проигрывает Kafka при: нужна долгосрочная retention (event sourcing), горизонтальное масштабирование throughput, интеграция с Kafka Connect (CDC из PostgreSQL), stream processing с Kafka Streams. Выигрывает при: Redis уже в стеке, нагрузка до 100K msg/s, нужна простота операций, задержки <1ms критичны.
Главное преимущество Redis Streams над Kafka для стартапа?
Паттерны применения Redis Streams
Activity feed - классический use case. Instagram, Twitter, TikTok строят ленты через fan-out. Redis Streams подходит для intermediate-слоя: событие публикуется в Stream, воркеры fan-out'ят его в Redis Sorted Sets (лента каждого подписчика).
Audit log - ещё один fit. Действия пользователей пишутся в Stream с MAXLEN для удержания последних N событий. Compliance читает через отдельную Consumer Group. Real-time dashboard - через третью группу. Три потребителя, один Stream, никакой дополнительной инфраструктуры.
Rate limiting + Streams: популярный паттерн. XADD с MAXLEN по времени - скользящее окно событий. Затем XLEN дает количество событий за период. Комбинация Redis Streams + sorted sets позволяет строить сложные rate limiters без Kafka.
Redis Pub/Sub и Redis Streams - это одно и то же, просто разный синтаксис
Pub/Sub - ephemeral без персистентности, Streams - append-only log с consumer groups и ACK
Pub/Sub теряет сообщения при offline-подписчиках. Streams сохраняют всё в PEL до XACK. Это принципиально разные гарантии доставки - как разница между UDP и TCP
Почему Redis Streams подходит для activity feed fan-out?
Связанные темы
Redis Streams в контексте messaging и хранения данных:
- Kafka — Аналог с партиционированием для высоких нагрузок
- Redis как хранилище — Базовые структуры данных Redis
- NATS — Альтернативный lightweight messaging
- Event-Driven Architecture — Streams как backbone EDA
Ключевые идеи
- Redis Pub/Sub - ephemeral, без persistence. При offline-подписчике сообщение теряется
- Redis Streams - append-only log с ID-адресацией, Consumer Groups и PEL для at-least-once
- XADD/XREADGROUP/XACK - триада для producer-consumer паттерна с гарантиями доставки
- Redis Streams vs Kafka: выбирай Streams когда Redis уже в стеке и нагрузка умеренная
Вопросы для размышления
- В каких случаях Redis Pub/Sub предпочтительнее Streams, несмотря на отсутствие гарантий?
- Как правильно выбрать MAXLEN для Stream: по количеству сообщений или по времени?
- Может ли Redis Streams заменить очередь задач (BullMQ) или это разные уровни абстракции?
Связанные уроки
- bt-13-kafka — Kafka - референс для сравнения со Streams
- bt-15-nats — NATS - аналогичный lightweight messaging
- db-19-redis — Redis как база - фундамент для понимания Streams
- bt-11-messaging-intro — Основы messaging перед Redis Streams
- bt-17-event-driven — Redis Streams как backbone event-driven систем
- net-55-message-queues