Транспорт бэкенда

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
Redis Streams и Pub/Sub

0

1

Войти