Redis: высокое потребление памяти — причины и решение
Redis отъедает всю оперативку, сервер начинает свопиться или ловит OOM-killer, а вы не понимаете, откуда столько данных. Redis высокое потребление памяти — типичная проблема эксплуатации, и причина почти всегда конкретна: нет лимита, ключи копятся без TTL, память фрагментирована или в базе завелись гигантские структуры. Разберём, как измерить, найти виновника и вернуть потребление под контроль.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Сначала измеряем, а не гадаем
Redis подробно рассказывает о своей памяти — начните с фактов. Команда INFO memory показывает всю картину.
redis-cli INFO memory
redis-cli INFO memory | grep -E 'used_memory_human|used_memory_rss_human|maxmemory_human|mem_fragmentation_ratio'
Ключевые метрики: used_memory — сколько занято логически данными; used_memory_rss — сколько реально отдала ОС процессу; maxmemory — установленный лимит (0 значит «без лимита»); mem_fragmentation_ratio — отношение rss к used, показатель фрагментации. Если maxmemory равен 0 — это первая и главная проблема: Redis будет расти, пока не съест всю память машины. Если mem_fragmentation_ratio заметно больше 1.5 — много памяти теряется на фрагментацию. Эти два числа сразу задают направление разбора.
Не пропускайте этот шаг ради быстрого «увеличу лимит и забуду». Высокое потребление памяти — это симптом, а причин у него несколько принципиально разных, и лечатся они по-разному: отсутствие лимита, забытые TTL, гигантские ключи и фрагментация требуют совершенно разных действий. Если добавить оперативки, не разобравшись, база просто дорастёт до нового потолка за то же время. Поэтому сначала снимите метрики и определите, с каким из четырёх сценариев вы имеете дело, и только потом принимайте решение.
Причина первая: не задан maxmemory
Без лимита Redis не знает, когда остановиться, и растёт до последнего байта — а дальше приходит OOM-killer и убивает процесс, что для хранилища катастрофа. Установка лимита обязательна на любом продакшене.
maxmemory 2gb
maxmemory-policy allkeys-lru
Задайте лимит с запасом под систему: если на сервере 4 ГБ, не ставьте Redis 4 ГБ — оставьте память ОС и на накладные расходы, разумно 2.5–3 ГБ. Применить без перезапуска:
redis-cli CONFIG SET maxmemory 2gb
redis-cli CONFIG SET maxmemory-policy allkeys-lru
Не менее важна политика вытеснения maxmemory-policy — что делать при достижении лимита. noeviction (по умолчанию) отдаёт ошибку на запись, но не удаляет ничего — база встаёт. Для кэша нужен allkeys-lru (вытеснять давно неиспользуемые) или allkeys-lfu (реже используемые). Для хранилища с TTL — volatile-lru. Без корректной политики лимит либо бесполезен, либо ломает запись.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPS под базы данныхПричина вторая: ключи без TTL копятся вечно
Очень частый сценарий: приложение пишет в Redis временные данные — сессии, кэш, токены — но не ставит им срок жизни. Ключи накапливаются и никогда не удаляются, память растёт линейно со временем. Проверьте, сколько ключей без TTL.
redis-cli DBSIZE
redis-cli INFO keyspace
# сколько ключей без срока жизни (выборочно)
redis-cli --scan --pattern '*' | head -100 | while read k; do echo "$(redis-cli TTL "$k") $k"; done | grep '^-1'
TTL со значением -1 означает «живёт вечно». Если таких ключей масса, а по смыслу они временные — приложение забывает ставить EXPIRE. Лечение на стороне приложения: писать значения командой с TTL, например SET key value EX 3600, или добавлять EXPIRE key 3600 после записи. Для уже накопившегося мусора проставьте TTL пачкой скриптом. Забытый TTL — причина номер один медленного роста памяти на кэширующих Redis.
Причина третья: большие ключи
Иногда память съедают не миллионы мелких ключей, а несколько гигантских: список на миллионы элементов, хэш с сотнями тысяч полей, огромная строка. Один такой ключ способен занять больше, чем вся остальная база. Найдите крупнейшие ключи встроенным анализатором.
redis-cli --bigkeys
redis-cli --memkeys
redis-cli MEMORY USAGE имя_ключа
--bigkeys пройдёт по базе и покажет самые большие ключи каждого типа. Обнаружив монстра, решайте по ситуации: разбить большую структуру на части, вынести редкие данные в основную базу, ограничить рост списка (LTRIM), или пересмотреть модель хранения. Большие ключи вредны не только памятью — операции над ними блокируют Redis и тормозят всё остальное. Держите структуры компактными: это одновременно и про память, и про скорость.
Учтите нюанс запуска --bigkeys и --memkeys на нагруженной базе: они сканируют весь набор ключей, и на больших базах это создаёт заметную дополнительную нагрузку. По возможности запускайте анализ в период низкой активности или на реплике, а не на основном узле в час пик. Команда использует безопасный SCAN и не блокирует сервер намертво, но лишний проход по миллионам ключей всё равно ощутим, и на проде это стоит планировать, а не запускать импульсивно в разгар нагрузки.
Причина четвёртая: фрагментация памяти
Если used_memory умеренный, а used_memory_rss намного больше (mem_fragmentation_ratio > 1.5), память теряется на фрагментацию: аллокатор держит освобождённые куски, не отдавая их ОС. Это типично после массового удаления ключей или частой перезаписи значений разного размера.
redis-cli INFO memory | grep mem_fragmentation_ratio
redis-cli MEMORY DOCTOR
MEMORY DOCTOR человеческим языком подскажет, есть ли проблема. Для борьбы с фрагментацией в современных версиях Redis есть активная дефрагментация — включите её, и Redis будет постепенно уплотнять память на лету:
activedefrag yes
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
Активная дефрагментация тратит немного CPU, но возвращает память ОС без перезапуска. Если версия старая и дефрага нет, помогает контролируемый рестарт (данные восстановятся из AOF/RDB) — но это крайняя мера. Обратите внимание: фрагментация меньше 1 (rss меньше used) означает, что часть данных ушла в своп — это гораздо хуже, разберитесь с лимитом памяти немедленно.
Профилактика и правильный сайзинг
Разовая чистка не спасёт, если причина системная. Стройте эксплуатацию так, чтобы память не убегала. Всегда задавайте maxmemory с запасом под ОС и адекватную политику вытеснения. Приучите приложение ставить TTL на всё временное — это снимает большинство проблем роста. Мониторьте used_memory и mem_fragmentation_ratio, заведите алерт при приближении к лимиту.
# быстрый снимок для мониторинга
redis-cli INFO memory | grep -E 'used_memory_human|maxmemory_human'
Оцените реальные потребности: если данных объективно много и они все нужны, проблема не в настройках, а в объёме — тогда честный ответ это больше RAM на сервере. Redis держит всё в памяти, и никакие политики не создадут её из воздуха. Для растущего проекта заранее берите сервер с запасом оперативки, чтобы не упираться в лимит на пике. На машине с достаточной RAM и заданными лимитами Redis работает стабильно и предсказуемо.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPS под базы данныхОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Почему Redis съедает всю память сервера?
Скорее всего, не задан maxmemory — без лимита Redis растёт до последнего байта и попадает под OOM-killer. Установите лимит с запасом под ОС и выберите политику вытеснения allkeys-lru для кэша.
Память растёт со временем, хотя нагрузка не меняется. В чём дело?
Классический признак ключей без TTL: приложение пишет временные данные, но не ставит срок жизни, и они копятся вечно. Проверьте TTL ключей, добавьте EXPIRE или пишите с EX на стороне приложения.
used_memory небольшой, а процесс занимает вдвое больше. Почему?
Это фрагментация памяти (mem_fragmentation_ratio > 1.5): аллокатор не отдаёт освобождённые куски ОС. Включите activedefrag yes — Redis уплотнит память на лету без перезапуска.
Как найти, что именно занимает память?
Запустите redis-cli --bigkeys для поиска крупнейших ключей и MEMORY DOCTOR для общей диагностики. Часто виноваты несколько гигантских структур, которые к тому же тормозят весь сервер.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.