Сколько памяти жрет Redis? Формула, примеры и точный калькулятор
- Redis расходует на каждую строку минимум 80 байт служебных данных, не считая полезных полей.
- Для 1 млн ключей с 50-байтовыми значениями Redis потребуется ~300 МБ ОЗУ.
- Использование типов данных, отличных от строк, может увеличить расход памяти в 2-5 раз.
- Наибольший прирост дают хеши с малым числом полей (ziplist даёт до 70% экономии).
- Команда MEMORY USAGE — ваш главный инструмент отладки.
- Базовая формула расхода памяти Redis
- Подробная формула с учётом типов данных
- Пошаговый пример расчёта для 1 миллиона ключей
- Подводные камни: что может неожиданно сожрать память
- Как отлаживать расход памяти: команды и инструменты
- Оптимизация: как уменьшить расход памяти на 30–70%
- Типичные ошибки при расчёте памяти Redis
- Калькулятор и бенчмарки: как проверить свой сценарий
- Заключение: главные правила экономии памяти в Redis
Базовая формула расхода памяти Redis
Redis хранит данные в оперативной памяти, и каждый ключ/значение обрастает служебными структурами. Минимальный расход на одну строку (ключ+значение) можно оценить как:
Где 64 байта — служебная нагрузка на запись (тип, флаги, срок жизни), 8 байт — указатель на словарь, плюс фактические строки. Для целых чисел (int) значение может храниться в самом указателе (до 2^31). На 2026 год это правило не изменилось: Redis продолжает использовать словарь с 64-байтной записью.
Пример: ключ "user:123" (9 байт), значение "active" (6 байт). Реальный расход ≈ 64 + 8 + 9 + 6 = 87 байт. Но это без учёта выравнивания и фрагментации аллокатора памяти (jemalloc), который может дать ещё 10-30% сверху.
Подробная формула с учётом типов данных
Для точного расчёта нужно учитывать тип данных Redis. Ниже — основные варианты:
| Тип Redis | Базовая структура | Доп. расход на элемент | Пример (1 тыс. элементов) |
|---|---|---|---|
| String (raw) | 64 + len(k) + len(v) | 0 | ~87 тыс. байт |
| String (int, до 2^31) | 64 + len(k) + 0 (value внутри указателя) | 0 | ~73 тыс. байт |
| Hash (ziplist, до 512 полей) | 64 + len(k) + сумма размера всех пар | 2 байта на элемент | ~64 + 9 + 2*1000 = 2073 байт |
| Hash (hashtable, больше 512 полей) | 64 + len(k) + таблица entries | 32 байта на entry | ~64 + 9 + 32*1000 = 32073 байт |
| List (quicklist) | 64 + len(k) + узлы quicklist | 24 байта на элемент | ~64 + 9 + 24*1000 = 24073 байт |
| Set (intset, до 512 целых) | 64 + len(k) + массив int | 4 байта на элемент | ~64 + 9 + 4*1000 = 4073 байт |
| Set (hashtable) | 64 + len(k) + таблица | 32 байта на элемент | ~64 + 9 + 32*1000 = 32073 байт |
| Sorted Set (ziplist, до 128 эл.) | 64 + len(k) + сумма пар(member+score) | 2 байта на элемент | ~64 + 9 + 2*1000 = 2073 байт |
| Sorted Set (skiplist) | 64 + len(k) + таблица + уровни | ~68 байт | ~64 + 9 + 68*1000 = 68073 байт |
Все цифры — на 2026 год. Важно: Redis использует jemalloc, который выделяет память блоками по степени двойки (16, 32, 48, 64, 80 и т.д.). Поэтому реальный расход может быть округлён вверх до ближайшего блока.
Пошаговый пример расчёта для 1 миллиона ключей
Рассчитаем память для типового сценария: кэш сессий. 1 млн ключей вида "session:uuid" (36-символьный UUID + префикс, всего 45 байт), значение — JSON 200 байт. Тип — String.
- Расход на ключ: 64 (запись) + 8 (указатель) = 72 байта.
- Плюс длина ключа: 45 байт = 117 байт.
- Плюс длина значения: 200 байт = 317 байт на запись.
- Учитывая jemalloc, округляем каждый "запись+данные" до ближайшего блока: 317 → 320 байт.
- На 1 млн записей: 320 * 1 000 000 = 320 000 000 байт ≈ 305 МБ.
- Добавляем служебный словарь: Redis хранит все ключи в глобальном словаре (ещё ~4 байта на ключ) = 4 МБ.
Итого: ~309 МБ. Плюс replication buffers, slowlog, client-буфера — может быть до 350 МБ.
Для проверки используйте Калькулятор расхода памяти Redis — он автоматически учтёт типы данных и аллокацию.
Подводные камни: что может неожиданно сожрать память
Многие разработчики удивляются, почему Redis ест в 2 раза больше ожидаемого. Типичные ловушки:
1. Срок жизни (TTL). Каждый ключ с TTL добавляет 8 байт на таймер. Если у всех ключей разный TTL — эти 8 байт превращаются в 8 МБ на 1 млн ключей.
2. Хеши со счётчиками. Если в хеше каждое поле — целое число, Redis может хранить его как int, но при превышении порога (512 полей или 64 байт на поле) переключается на hashtable, увеличивая расход в 5 раз.
3. Фрагментация. Redis использует jemalloc, который не дефрагментирует. После многих апдейтов значений разного размера память дробится. Разница занятой и используемой памяти может достигать 30%.
Следите за метриками used_memory и used_memory_rss в INFO. Если RSS > used_memory на 30% — фрагментация критична. Включите activedefrag yes (доступно с Redis 5.0, сейчас 7.x — ещё лучше).
Содержит ключ, значение, типы, флаги, TTL, указатель на следующую запись.
Ссылка на строку ключа в памяти.
Фактическая строка ключа, например 'user:123' — 9 байт.
Ссылка на объект значения.
Для строк — строка, для хеша — ziplist или hashtable и т.д.
Как отлаживать расход памяти: команды и инструменты
Redis предоставляет встроенные команды для точной диагностики:
| Команда | Что показывает | Пример использования |
|---|---|---|
| MEMORY USAGE <key> | Реальный размер ключа в байтах с учётом служебных структур | MEMORY USAGE session:abc123 → (integer) 320 |
| MEMORY STATS | Сводку по используемой памяти, фрагментации и т.д. | MEMORY STATS → ... overhead.hashtable.main: 4194304 |
| INFO memory | Агрегированные метрики: used_memory, peak, fragmentation ratio | INFO memory → # Memory used_memory:524288000... used_memory_rss: 629145600 |
| MEMORY PURGE | Принудительно очищает свободные страницы (только Redis 4.0+) | MEMORY PURGE → OK |
| DEBUG OBJECT <key> | Показывает внутреннюю кодировку (int, embstr, raw) и ссылочный счётчик | DEBUG OBJECT user:1 → Value at:0x7f... refcount:1 encoding:embstr serializedlength:6 |
Также полезно смотреть bigkeys с помощью redis-cli --bigkeys — найдёт самые прожорливые ключи.
Онлайн-инструменты, такие как Калькулятор расхода памяти Redis, позволяют быстро прикинуть бюджет памяти без запуска Redis.
🧠 Проверьте свои знания о памяти Redis
1. Сколько байт служебной нагрузки (overhead) минимально добавляет каждая запись Redis?
2. Какой тип данных Redis даёт наибольшую экономию при хранении объекта с 10 полями?
3. Какая команда показывает точный размер конкретного ключа в Redis?
4. Что означает, когда used_memory_rss значительно больше used_memory?
5. Какое максимальное количество полей в хеше, при котором он хранится как ziplist (по умолчанию)?
Оптимизация: как уменьшить расход памяти на 30–70%
Несколько проверенных техник:
- Хеши вместо строк. Если у вас объект с 10-20 полями, храните его как хеш:
HSET user:1 name "John" age 30— при малом количестве полей (до 512) Redis использует ziplist, что даёт экономию до 70% по сравнению с JSON-строкой. - Целые ключи. Вместо "user:1000000" используйте просто число 1000000. Redis может хранить int внутри указателя, экономя 9-30 байт на ключе.
- Выставляйте TTL, если данные не вечные. Сокращает количество мусора, но не забывайте про накладные расходы на таймер.
- Используйте list вместо set для списков без проверки дубликатов. Set (hashtable) дороже list (quicklist) на 30%.
- Обновляйте Redis до версии 7.2+. В ней улучшена работа с памятью: compact memory for small keys, новые кодировки.
После оптимизации пересчитайте потребление на калькуляторе.
Типичные ошибки при расчёте памяти Redis
Даже опытные DevOps ошибаются. Вот топ-5:
- Не учитывают служебные данные (overhead). Многие считают только размер value, забывая про 80+ байт на каждый ключ.
- Путают used_memory и used_memory_rss. Первое — реальное занятое место, второе — выделенное ОС (с учётом фрагментации). Разница может быть 2x.
- Игнорируют настройки maxmemory-policy. Если политика "allkeys-lru", Redis может вытеснять ключи, увеличивая фрагментацию.
- Считают 1 байт на символ для Unicode. В Redis строки байтовые, кириллица в UTF-8 занимает 2 байта на символ.
- Забывают про репликацию и буферы. На master+slave каждая запись дублируется. Plus client output buffer может добавить 10% к памяти.
Используйте команды из предыдущего раздела, чтобы проверить реальное потребление, а не гадать.
Калькулятор и бенчмарки: как проверить свой сценарий
Для точных цифр лучше всего прогнать тесты на ваших данных. Проще всего — написать маленький скрипт на Python, который генерирует 1000 ключей и смотрит used_memory до и после:
import redis
r = redis.Redis()
before = r.info('memory')['used_memory']
for i in range(1000):
r.set(f'key:{i}', 'x'*200)
after = r.info('memory')['used_memory']
print(f'На 1000 ключей: {(after-before)/1024:.2f} КБ')Разделите на 1000, умножьте на 1 000 000 — получите примерное потребление для млн. Но аллокатор может вести себя нелинейно, поэтому для серьёзного проекта используйте Калькулятор расхода памяти Redis, который учитывает jemalloc и типы данных.
Также полезно прогнать официальный бенчмарк с вашими данными: redis-benchmark -P 16 -n 100000 -r 100000 -d 200 -t set. Но помните, что бенчмарк не отражает реальную фрагментацию при долгой работе.
Заключение: главные правила экономии памяти в Redis
- Используйте хеши для объектов — они дают наибольшую экономию.
- Выбирайте целочисленные ключи, если это возможно.
- Устанавливайте TTL только когда это действительно нужно, и группируйте одинаковые TTL.
- Следите за фрагментацией (used_memory_rss / used_memory). Если > 1.5, включите activedefrag.
- Перед закупкой железа — прикиньте бюджет через калькулятор.
Помните: Redis — не бездонная бочка. 1 ГБ ОЗУ на современном сервере стоит дёшево, но при 10 млрд ключей один только overhead может сожрать 800+ ГБ. Планируйте заранее.
🧮 Посчитайте сами — инструменты по теме
🧭 Разделы по теме
Частые вопросы
Какой минимальный размер ключа в Redis?
Минимальный размер ключа — 1 байт (пустая строка недопустима). Но с учётом служебных данных каждая запись весит не менее 64+8+len(key) байт.
Сколько памяти занимает 1 миллион пустых ключей в Redis?
Каждый ключ без значения занимает ~72 байта (64 служебных + 8 указатель). Для 1 млн ключей: 72 МБ плюс служебный словарь (~4 МБ). Итого ~76 МБ.
Почему Redis использует больше памяти, чем я ожидаю?
Основные причины: фрагментация jemalloc (RSS может быть на 30% выше), служебные структуры (overhead 80+ байт на запись), дублирование при репликации, а также буферы клиентов. Используйте MEMORY STATS для деталей.
Как уменьшить расход памяти Redis без потери данных?
Переходите на хеши для объектов, используйте целочисленные ключи, включайте activedefrag, снижайте hash-max-ziplist-entries, используйте list вместо set. Также можно уменьшить maxmemory и настроить вытеснение.
Что делать, если Redis упал с OOM (Out of Memory)?
Проверьте maxmemory и политику вытеснения. Увеличьте maxmemory или смените политику на allkeys-lru. Удалите большие ключи (команда UNLINK). Включите swap (не рекомендуется) или добавьте память на сервере.
Какая разница между used_memory и used_memory_rss?
used_memory — реально занятая память (сумма всех данных). used_memory_rss — выделенная ОС (с фрагментацией). Если RSS > used_memory на 50% — сильная фрагментация, включите activedefrag.
Как проверить, какой ключ съел больше всего памяти?
Используйте redis-cli --bigkeys или команду MEMORY USAGE для каждого ключа в цикле. На реальных данных — скрипт с SCAN и MEMORY USAGE.
Работают ли эти расчёты для Redis Cluster?
Да, принципы те же, но каждый шард — независимый инстанс Redis. Общий расход — сумма по всем шардам. Плюс служебная память на кластерные узлы (слоты, gossip).
Источники и нормативные документы
- Документация Redis по командам MEMORY
- Статья Redis memory optimization на официальном сайте
- Исходный код Redis (структуры словаря)