Модуль 4. Мониторинг Redis-очереди: метрики, SLOWLOG, Prometheus, алерты

Цель модуля: научиться видеть состояние Redis-очереди по приборам: какие метрики INFO действительно важны для стримов, как поймать деградацию памяти до OOM, как поднять redis-exporter с Prometheus и какие алерты ставить — так, чтобы они не орали по пустякам.

Перед началом: Модули 1–3. Docker, базовое знакомство с Prometheus. Инструменты: стенд boilerplate (make up-obs), oliver006/redis_exporter, Prometheus, Grafana (опционально). Трудоёмкость: ~8–10 ч (теория 4 ч · практика 4 ч · квиз 1 ч).


📖 4.1. Карта метрик: что смотреть для очереди

У Redis нет «одной метрики здоровья» — есть четыре группы, и для очереди важна каждая по-своему.

Память (INFO memory) — первая причина отказов Redis-очередей:

bash
redis-cli INFO memory | grep -E "used_memory_human|used_memory_rss|maxmemory|maxmemory_policy|mem_fragmentation_ratio"
  • used_memory vs maxmemory — сколько осталось до eviction/OOM;
  • mem_fragmentation_ratio (>1.5 — алерт): память, которую ОС не может вернуть аллокатору; типично после пиков больших записей;
  • maxmemory_policy — для очереди должен быть noeviction: политики типа allkeys-lru начнут молча удалять ваш стрим, чтобы не умереть.

Ключи и eviction (INFO stats): evicted_keys, expired_keys. evicted_keys > 0 при noeviction невозможны (записи начнут падать с ошибкой), а при других политиках — красный флаг: кеш выдавливает данные.

Персистентность (INFO persistence):

bash
redis-cli INFO persistence | grep -E "rdb_last_bgsave_status|aof_last_write_status|aof_last_bgrewrite_status"

Статус не ok — ваш «гарант» перестал работать; у очереди это дежурная тревога: писать продолжаем, а переживём ли рестарт — уже вопрос.

Репликация (INFO replication): master_link_status:up у реплик, master_last_io_seconds_ago (связь жива?), master_repl_offset и replica_repl_offset — их разница и есть лаг в байтах.

Стримы — здесь Redis метрики не собирает: состояние очереди живёт в XINFO:

bash
redis-cli XINFO GROUPS orders
# name       consumers  pending  last-delivered-id  lag
# billing    3          12       1712345678901-0    4

lag (новое в Redis 7) — сколько записей ещё не доставлено группе; pending — «займ» в руках консьюмеров. Но самое важное число XINFO не отдаёт — возраст хвоста: насколько поздно вы обрабатываете:

bash
# ID первой записи содержит unix-миллисекунды — возраст = now - ms(ID)
redis-cli XRANGE orders - + COUNT 1

Скрипт-хелпер для экспорта stream_age — в практике.


📖 4.2. SLOWLOG: три команды, которые вы найдёте в нём первыми

bash
redis-cli CONFIG SET slowlog-log-slower-than 10000  # порог в микросекундах (10 мс)
redis-cli SLOWLOG GET 10

В очереди на Streams чаще всего ловятся:

  • KEYS/SCAN с широким матчем — отладка, забытая в проде;
  • XRANGE/XREAD без COUNT по выросшему стриму — чтение всей истории;
  • XADD в раздувшийся стрим с MaxLen точным (без ~) — точная обрезка при каждой записи дороже аппроксимации;
  • Lua-скрипт, ползающий по большому диапазону — воображаемый «атомарный дедуп», который латентностью валит весь Redis (одна блокирующая операция стопорит всех: Redis однопоточный).

Правило эксплуатации: slowlog-log-slower-than 10000 в проде включён всегда, SLOWLOG RESET — после разбора (чтобы не привыкать к шуму).


📖 4.3. Поднимаем наблюдаемость: exporter + Prometheus

Специально для этого курса в стенде есть профиль наблюдаемости:

bash
make up-obs      # Redis + redis_exporter (:9121) + Prometheus (:9090)
  • redis-exporter конвертирует INFO/XINFO в метрики Prometheus: redis_memory_used_bytes, redis_evicted_keys_total, redis_connected_clients, redis_replication_*, latency-гистограммы (redis_commands_duration_seconds_total при -include-system-metrics);
  • Prometheus скрейпит exporter каждые 15 с (config/prometheus.yml).

Ключевые метрики в терминах Prometheus (запомните имена — с ними работают дашборды и алерты):

МетрикаО чёмПорог-ориентир
redis_memory_used_bytes / redis_memory_max_bytesблизость к лимиту> 70 % — тревога, > 85 % — критика
redis_mem_fragmentation_ratioфрагментация> 1.5 устойчиво
redis_evicted_keys_totalвыдавленные ключилюбое устойчивое увеличение
redis_rdb_last_bgsave_statusснапшоты!= 1
redis_aof_last_write_statusAOF!= 1
redis_connected_clientsклиентырезкий рост = утечка соединений
redis_blocked_clientsожидающие блокирующих операцийустойчиво > 0 при XREAD Block

Для метрик очереди (stream lag/pending/age) exporter из коробки даёт часть (redis_stream_* в новых версиях), остальное — своим tiny-exporter'ом: скрипт из §4.1 отдаёт числа в формате Prometheus — в практике подключим его как третий скрейп-таргет.


📖 4.4. Дашборд: восемь панелей, которых хватит

Минимальный операторский дашборд очереди (порядок панелей = порядок взгляда при инциденте):

  1. Throughput: XADD-ы vs XACK-и в секунду (две кривые рядом — разрыв = растущий займ);
  2. Stream age: возраст первой необработанной записи (секунды);
  3. Pending & lag по группам;
  4. Память: used/max + fragmentation;
  5. Evictions & expirations (должны быть нулевые);
  6. Latency: p50/p99 по командам (redis_commands_duration_*);
  7. Репликация: link status + лаг;
  8. Persist: rdb/aof status.

Совет из практики: панели 1–3 — «наша очередь», 4–8 — «наш Redis». При инциденте сначала смотрят 1–3 (проблема обработки), и только потом 4–8 (проблема сервера) — большинство «очередь встала» это первые три.


📖 4.5. Алерты: что ставить и где шуметь нельзя

Правило: алерт ставится на симптом для человека, а не на любую метрику для красоты. Для очереди на Redis работающая пятёрка:

АлертУсловиеПочему так
Stream age растётage > 60 с в течение 5 минГлавный симптом: вы отстаёте по времени, а не по количеству
Pending не сбрасываетсяpending той же группы > 1000 и не падает 10 минВоркеры держат, но не подтверждают: зависший/медленный обработчик
Память на подходеused/max > 85 % 5 минДо OOM/eviction остались считанные минуты
Evictionsrate > 0 5 мин при любой политикеМолчаливое выдавливание данных
Persist сломанrdb/aof status != ok 10 минРаботаем без страховки

Анти-примеры (не ставить): «lag > 0» (это норма при живом трафике), «used_memory > 1 ГБ» (абсолютный порог без привязки к maxmemory), «rejected_connections > 0» (нормальный backpressure пула, пока не устойчиво).


💻 Практика

  1. Поднимите наблюдаемость: make up-obs, проверьте http://localhost:9090/targets — Redis-таргет должен быть UP.
  2. tiny-exporter очереди (±40 строк на Go/Python): читает XINFO GROUPS orders + первую запись XRANGE, считает stream_age_seconds, stream_pending, stream_lag, отдаёт на /metrics (порт 9130), добавьте его в config/prometheus.yml как второй таргет.
  3. Разгон и деградация: продюсер на 200 записей/с и воркер с искусственной задержкой 200 мс (потолок ~5×200 мс/с); наблюдайте в Prometheus (rate() по счётчикам): age растёт, pending растёт.
  4. Ложный и настоящий алерт: сформулируйте PromQL для пятёрки из §4.5 (черновики — в config/alerts.yml), проверьте, что «lag > 0» у вас в правилах отсутствует.
  5. Сломайте персистентность: остановите/возобновите AOF-запись (CONFIG SET appendonly no, крупный BGREWRITEAOF) — поймайте изменение статуса на дашборде. Убедитесь, что алерт звонит один раз, а не каждые 15 секунд (for: в правиле).

Артефакт: config/prometheus.yml + config/alerts.yml + скриншот дашборда из Grafana (или Prometheus graph) с растущим age.


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

1. maxmemory_policy = allkeys-lru на Redis-очереди. Чем это опасно?
2. Почему алерт «lag > 0» — плохой?
3. Какая метрика лучше всего отвечает на вопрос «мы отстаём?»
4. Что искать в SLOWLOG первой очередью для Redis-очереди?

✅ Итоги модуля

ТемаГлавное
МетрикиЧетыре группы: память (noeviction!), stats, persist, репликация; очередь — через XINFO + возраст хвоста
SLOWLOGВключён всегда (10 мс); топ-виновники — KEYS, широкие XRANGE, тяжёлый Lua
Стендredis_exporter + Prometheus (make up-obs) + tiny-exporter для метрик очереди
Дашборд8 панелей: throughput, age, pending — первыми; серверные — вторыми
АлертыПять симптомных алертов с for:; антипример «lag > 0» — не ставить

🔗 Мостик к Модулю 5

Мы видим систему. Теперь — читаем её в момент боли: инциденты (big/hot keys, eviction под нагрузкой, OOM, лаг реплики, blocked clients): симптом → метрика → причина → лечение, каждый — воспроизводимый на стенде. А закроет курс модуль о том, когда Redis-очередь — осознанное решение, а когда — отложенный инцидент.