Производительность 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);
- Рехешинг гигантских коллекций: при росте хеш-таблиц большой коллекции; тот же ответ — не расти до гигантов.
Практика
- Постройте профиль памяти тестовой БД:
--bigkeysи--memkeys; найдите топ-5 ключей и объясните их происхождение. - Создайте хеш на 1 млн полей: замерьте HGETALL (время блокировки), затем DEL против UNLINK (паузы на клиентах PING).
- Разбейте гиганта на 16 шардов и повторите HGETALL-подобную операцию порциями — убедитесь, что пауз нет.
- Сравните redis-benchmark и memtier на одном конфиге: расхождения p99 — и почему.
Мини-квиз
1. Почему benchmark в лаборатории ×2 быстрее прода? — Другие размеры значений, распределение ключей, политика eviction, персистентность, RTT.
2. Big key под политикой eviction — в чём опасность? — Вытеснение большого ключа — дорогая операция; при lazy-free выключенном — стопор.
3. Первый инструмент при жалобе «иногда 200 мс»? — Slowlog + latency monitor (модуль 6), но big keys проверить тоже: они дают спорадические стопоры.