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

Модуль 05 / Урок 23 из 27

Benchmarking и охота на big keys

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

Производительность Redis — это измерение, а не гадание. Учимся строить честные тесты и находить ключи, которые разрушают латентность и память.

redis-benchmark и memtier

# Классика: 200k операций SET/GET, значение 256б, 50 соединений, 4 пайплайна
redis-benchmark -h host -n 200000 -c 50 -d 256 -P 4 -t set,get

# Своё распределение ключей и своя команда
redis-benchmark -n 100000 -c 20 "HGET user:{rand}:profile field1"

# memtier_benchmark: ближе к реальному миксу, richer статистика p99
memtier_benchmark -s host -p 6379 --ratio 1:1 -c 10 -t 4 -d 256 \
  --key-pattern R:R --test-time 60

Как делать честный тест

  • Реалистичные значения: размер данных влияет сильнее всего (embstr vs raw, listpack vs hashtable);
  • Реалистичное распределение ключей: R:R (равномерный) переоценивает кеш-эффект; воспроизводите «горячую головку» (ZIPF через memtier: --key-pattern Z:Z);
  • Смотрите p99/p999, а не среднее: хвосты прячут fork, eviction, рехешинг;
  • Тепловой прогрев и несколько прогонов с отбрасыванием первого;
  • Тестируйте с тем же maxmemory, политикой eviction и персистентностью, что в проде — иначе цифры другого мира.

Ориентиры производительности

  • Простой GET/SET на приличном железе: 100–200k ops/s на ядро без пайплайна, 500k–1M+ с пайплайном;
  • Латентность команды: 50–200 микросекунд p50 в одной ДЦ;
  • Ограничители: одно ядро исполнения, RTT сети, размер значений, персистентность (fsync!).

Big keys: тихие убийцы

Ключ с миллионом элементов вредит всем сразу: любой HGETALL — O(N) стопор; DEL — долгая блокировка; eviction/expire — медленное освобождение; миграция слотов и репликация таскают его целиком; память фрагментируется.

Поиск

# Семплирующий отчёт по типам (безопасен в проде, идёт через SCAN)
redis-cli --bigkeys
[00.12%] Biggest hash so far 'user:sessions' with 340000 fields

# По потреблению памяти (медленнее, точнее по байтам)
redis-cli --memkeys
# Точечный замер
MEMORY USAGE user:sessions SAMPLES 0

Лечение

  • Шардирование коллекции: hash:{id}:{shard 0..15} — каждая часть нормального размера;
  • Частичное чтение: HSCAN/LRANGE/SSCAN порциями вместо HGETALL;
  • Ленивое удаление: UNLINK вместо DEL; lazyfree-lazy-expire yes;
  • Пересмотр модели: миллион полей в одном хеше почти всегда означает «список задач, притворяющийся хешем» — им должен быть Stream/List или внешняя БД;
  • Профилактика: алерты на размер коллекций (счётчики SCARD/HLEN в метриках приложения) — дешевле, чем поиск в 3 часа ночи.
# Безопасная разборка гиганта на части (на лету)
# 1. HSCAN копируем в новые хеши-шарды
# 2. UNLINK старый

Latency-хвосты: ещё два источника

  • Истечение пачек TTL: тысячи ключей одной секунды — активный сборщик мусора съест CPU; лечится джиттером TTL (урок 2.2/2.3);
  • Рехешинг гигантских коллекций: при росте хеш-таблиц большой коллекции; тот же ответ — не расти до гигантов.

Практика

  1. Постройте профиль памяти тестовой БД: --bigkeys и --memkeys; найдите топ-5 ключей и объясните их происхождение.
  2. Создайте хеш на 1 млн полей: замерьте HGETALL (время блокировки), затем DEL против UNLINK (паузы на клиентах PING).
  3. Разбейте гиганта на 16 шардов и повторите HGETALL-подобную операцию порциями — убедитесь, что пауз нет.
  4. Сравните redis-benchmark и memtier на одном конфиге: расхождения p99 — и почему.
Мини-квиз

1. Почему benchmark в лаборатории ×2 быстрее прода? — Другие размеры значений, распределение ключей, политика eviction, персистентность, RTT.

2. Big key под политикой eviction — в чём опасность? — Вытеснение большого ключа — дорогая операция; при lazy-free выключенном — стопор.

3. Первый инструмент при жалобе «иногда 200 мс»? — Slowlog + latency monitor (модуль 6), но big keys проверить тоже: они дают спорадические стопоры.