Программа курса

Модуль 03 / Урок 12 из 27

Streams: журнал сообщений

Теория и практика

Stream — апенд-онли журнал записей с монотонными ID, хранящийся в датасете Redis (а значит персистентный и реплицируемый). Это «мини-Kafka» внутри Redis, и почти всё в нём вращается вокруг идеи ID.

Записи и ID

XADD orders * product sku-777 qty 2 total 1980
1717000000000-0        # ID: миллисекунды-секвенция
  • Формат ID: мс-секвенция. * просит Redis сгенерировать ID сам (гарантированно монотонный даже при переводе часов назад);
  • ID можно задавать вручную: XADD orders 1717000000005-0 ... — полезно для миграций и реплея;
  • Запись — это плоский словарь «поле-значение»; не бывает записей без полей;
  • Чтение диапазоном: XRANGE orders - + COUNT 10, а также XREVRANGE, и «от времени»: XRANGE orders 1717000000000 +.

Чтение: диапазоны и режим подписки

# Всё, что есть
XRANGE orders - +

# Блокирующее чтение новых записей (как tail -f)
# $ = "только то, что появится ПОСЛЕ текущего момента"
XREAD BLOCK 5000 COUNT 100 STREAMS orders $

# С нескольких потоков разом
XREAD BLOCK 5000 STREAMS orders payments $ $

XREAD — это «голый» tail: каждый читатель сам помнит последний ID. Никто не мешает десяти читателям прочитать один и тот же поток независимо — поток не «съедается» чтением.

Удержание размера: MAXLEN и XTRIM

# При записи: обрезать до ~100k записей (тильда = приблизительно, быстрее)
XADD orders MAXLEN ~ 100000 * product sku-1 qty 1

# Периодическая обрезка отдельной командой
XTRIM orders MAXLEN ~ 100000
# Или по времени (Redis 6.2+): хранить последние 7 дней
XTRIM orders MINID ~ $(date -d '7 days ago' +%s)000-0
⚠️ Stream без обрезки растёт бесконечно и выест память. Стратегия retention — обязательная часть дизайн-дока потока: сколько записей/дней вам реально нужно.

Внутреннее устройство

Записи упакованы в listpack'и по ~100 штук, а дерево по префиксам ID (radix tree) ведёт к ним. Отсюда: дешёвый append в конец, эффективные диапазоны, компактное хранение. Счётчик длины — XLEN — O(1).

Ограничения самого потока

  • Полей в записи может быть много, но крупные значения раздувают память — тот же принцип, что и для ключей;
  • Нет «топиков» с динамическими подписками — канал вы создаёте сами ключом (orders — это просто ключ типа stream);
  • Конкуренция потребления и ACK — это consumer groups (следующий урок): один XREAD без групп не даёт «взять задание».

Практика

  1. Создайте поток, добавьте 100 записей скриптом, прочитайте диапазоны: последние 10 (XREVRANGE + COUNT 10), «за последнюю минуту» (XRANGE от now-60000).
  2. Запустите XREAD BLOCK 0 STREAMS s $ и добавляйте записи из другого терминала — убедитесь в realtime-поведении.
  3. Настройте retention: XADD с MAXLEN ~ 100 и убедитесь, что XLEN не растёт дальше ~120.
Мини-квиз

1. Что означает ID 1717000000000-0? — Миллисекунда Unix + секвенция внутри этой миллисекунды.

2. Двое читателей через XREAD — мешают друг другу? — Нет: чтение не удаляет записи, каждый читает поток независимо.

3. Зачем тильда в MAXLEN ~ 100000? — Приблизительная обрезка целыми узлами дерева — быстрее и почти не превышает лимит.