OOM command not allowed when used memory > maxmemory: как исправить ошибку Redis

Redis достиг лимита памяти: диагностика maxmemory и безопасное восстановление
Содержание 14 разделов

Сообщение OOM command not allowed when used memory > 'maxmemory' означает, что Redis достиг настроенного лимита памяти и отклонил команду, способную добавить данные. Чтение существующих ключей при этом часто продолжает работать, поэтому проблема выглядит странно: часть страниц открывается, а сессии, очереди, корзина или кеш перестают обновляться.

Перезапуск Redis иногда временно скрывает симптом, однако не объясняет, почему память закончилась. Надёжное исправление начинается с ответа на три вопроса: что хранится в Redis, какие ключи допустимо вытеснять и почему данные растут быстрее, чем освобождаются.

Как maxmemory связан с ошибкой OOM

Параметр maxmemory ограничивает объём памяти для набора данных Redis. При новой записи сервер сравнивает фактическое использование с лимитом и применяет выбранную политику maxmemory-policy. Политика noeviction сохраняет ключи, но отклоняет новые записи. Политики LRU, LFU и random могут освобождать место за счёт подходящих ключей [1].

Лимит нельзя приравнивать ко всей оперативной памяти процесса. Репликация, AOF, сетевые буферы и фрагментация требуют запаса. При сохранении RDB или переписывании AOF нагрузка на память также может временно вырасти [2]. Поэтому установка maxmemory почти в размер всей RAM создаёт риск уже на уровне операционной системы.

Что проверить до изменения конфигурации

Сначала сохраните фактическое состояние. Минимальный набор команд:

redis-cli INFO memory
redis-cli INFO stats
redis-cli CONFIG GET maxmemory
redis-cli CONFIG GET maxmemory-policy
redis-cli INFO keyspace

В разделе памяти важны used_memory, used_memory_dataset, used_memory_rss, коэффициент фрагментации и mem_not_counted_for_evict. В статистике посмотрите evicted_keys, expired_keys и число отклонённых команд. Высокий evicted_keys показывает постоянное давление на кеш, а нулевое вытеснение при OOM часто указывает на noeviction либо на политику volatile-* при отсутствии TTL.

Далее оцените распределение ключей: префиксы, объём крупных значений, средний TTL, число бессрочных записей. Команда KEYS * на рабочей базе способна надолго занять сервер. Для инвентаризации используют неблокирующий SCAN, выборочные проверки MEMORY USAGE и специализированные анализаторы.

Политика зависит от назначения Redis

Что хранитсяОбычная логикаГлавный риск
Восстанавливаемый кешTTL и вытеснение всех ключей по LRU или LFUСлишком частые промахи кеша и рост нагрузки на базу
Сессии пользователейTTL по сроку жизни сессии, запас памяти, контроль активных ключейНеожиданный выход пользователей из аккаунта
Очередь заданийОграничение длины, подтверждение обработки, отдельный контроль потребителейПотеря или повтор задания при неверной схеме
Постоянные данныеПланирование ёмкости, репликация и сохранность; вытеснение обычно недопустимоТихая потеря бизнес-данных

Одинаковая настройка для всех сценариев не подходит. Если один экземпляр Redis одновременно обслуживает кеш, сессии и очередь, безопаснее разделить нагрузки по разным базам или экземплярам с независимыми лимитами.

Как восстановить запись без опасных действий

  1. Остановите источник неконтролируемого роста. Это может быть зависшая очередь, ключ без TTL, массовый импорт или новый релиз.
  2. Удалите только подтверждённо восстанавливаемые данные. Перед очисткой проверьте префикс, владельца и способ повторного построения. FLUSHALL для общей рабочей базы почти всегда слишком груб.
  3. Верните срок жизни новым ключам. Исправление должно появиться в коде, иначе ручная очистка лишь переносит следующий OOM.
  4. Выберите политику вытеснения по смыслу данных. Для чистого кеша часто подходят allkeys-lru или allkeys-lfu. Для смешанной базы решение принимают после разделения классов ключей.
  5. Изменяйте лимит с запасом для процесса и ОС. Redis рекомендует учитывать служебные буферы и пиковое потребление [2].
  6. Закрепите конфигурацию. Изменение через CONFIG SET проверяют в работе, затем корректно сохраняют в конфигурационном файле или управляемом сервисе.

Почему простое увеличение maxmemory часто не помогает

Если ключи создаются без TTL или потребитель очереди отстаёт, новый лимит тоже будет заполнен. Аналогично фрагментация может оставаться высокой после удаления данных: аллокатор повторно использует свободные участки, но не обязан сразу возвращать память операционной системе [3]. В такой ситуации полезны анализ структуры ключей, плановый перезапуск реплики с переключением и корректировка модели данных.

Для сайта на «1С-Битрикс» отдельно проверяют, что хранится в Redis: кеш, PHP-сессии или оба класса. Ошибка сессий влияет на авторизацию и корзину, а ошибка кеша вызывает резкий рост запросов к базе. Логи приложения нужно сопоставить с графиком Redis, временем релиза и изменением количества ключей.

Как отличить рост данных от служебного расхода памяти

Показатель used_memory отвечает на вопрос, сколько памяти выделил Redis, но сам по себе не объясняет причину OOM. Для разбора полезно разделить набор данных, служебные структуры и фактическую память процесса. В INFO memory для этого есть used_memory_dataset, used_memory_overhead, used_memory_rss, used_memory_peak и показатели фрагментации. Если растёт именно used_memory_dataset, нужно искать новые или увеличивающиеся ключи. Если набор данных стабилен, а RSS заметно выше, причина может быть в фрагментации или в ранее пройденном пике нагрузки [5].

Отдельного внимания требует mem_not_counted_for_evict. Эта память не учитывается при принятии решения о вытеснении: к ней относятся, в частности, служебные буферы репликации и AOF. Поэтому экземпляр способен приблизиться к пределу RAM операционной системы, хотя значение, участвующее в сравнении с maxmemory, выглядит приемлемым. Снимок метрик нужно сопоставлять с состоянием persistence, репликации и объёмом записи в момент сбоя.

ПризнакВероятная причинаСледующий шаг
used_memory_dataset постоянно растётНовые ключи, значения без TTL, растущие списки или множестваРазобрать ключи по префиксам, размеру и сроку жизни
RSS значительно выше used_memoryФрагментация либо след от прежнего пикаПроверить used_memory_peak, MEMORY STATS и MEMORY DOCTOR
Растёт mem_not_counted_for_evictБуферы AOF или репликацииПроверить persistence, состояние реплик и скорость записи
Много evicted_keys, падает hit rateРабочий набор кеша не помещается в лимитПересмотреть TTL, объём кешируемых объектов и ёмкость
OOM есть, вытеснений нетnoeviction либо нет подходящих ключей для volatile-*Сверить политику и долю ключей с TTL

Как найти ключи, которые занимают память

SCAN перебирает ключи порциями и подходит для рабочего контура лучше, чем блокирующий KEYS *. При изменении набора данных во время обхода SCAN даёт ограниченные гарантии и может вернуть один ключ повторно, поэтому результат анализа используют как диагностическую выборку, а обработчик умеет распознавать повторы.

Полезный результат анализа — не перечень из сотен случайных ключей, а сводка по владельцам данных. Например: sess: создаёт модуль PHP-сессий, bitrix: относится к кешу приложения, queue: хранит задания, а rate: — счётчики ограничений. Для каждого префикса фиксируют число ключей, общий и максимальный размер, долю ключей без TTL, медианный срок жизни и скорость прироста. Так становится видно, что именно заполнит оставшуюся память через несколько часов или дней.

Большой ключ и большое количество маленьких ключей требуют разных исправлений. Один многомегабайтный объект обычно указывает на неограниченный список, набор или неудачную сериализацию. Миллионы мелких записей чаще появляются из-за слишком подробного ключа, отсутствующего удаления старых версий либо уникального идентификатора в ключе кеша. Простое удаление крупнейшего объекта во втором случае почти ничего не изменит.

Как связать всплеск памяти с приложением

Время возникновения OOM сопоставляют с релизом, импортом, рассылкой, фоновой задачей и ростом трафика. В INFO commandstats видны количество вызовов и суммарное время по командам. INFO keyspace показывает число ключей и средний TTL по логическим базам. Эти данные лучше собирать регулярно: одиночный снимок после аварии не покажет, росла база весь день или заполнилась за несколько минут.

Для расследования полезно добавить в приложение собственные признаки: название операции, класс ключа и результат записи. Полные значения, данные сессий и токены в журнал не помещают. Достаточно префикса, примерного размера, TTL и идентификатора запроса. Если после обновления число команд HSET или LPUSH выросло в несколько раз, а срок жизни соответствующих структур не ограничен, связь становится проверяемой.

Как рассчитать maxmemory с рабочим запасом

Лимит выбирают от доступной памяти узла, а не от текущего размера базы. Из общей RAM вычитают потребление операционной системы и соседних процессов, ожидаемый служебный расход Redis, запас для репликации и persistence, а также резерв на пик нагрузки. Официальная документация отдельно предупреждает: при интенсивной записи во время создания RDB или переписывания AOF потребление может существенно увеличиваться из-за механизма copy-on-write [2].

Расчёт проверяют на реальном профиле нагрузки. Если рабочий набор кеша занимает 6 ГБ, а узлу доступно 8 ГБ, установка maxmemory 7.8gb не создаёт безопасную конфигурацию: процессу и системе почти не остаётся места для буферов и пиков. Если же Redis хранит критичные данные с persistence, сначала подтверждают восстановление из резервной копии и поведение реплики, а затем меняют лимиты.

Для реплики нужен собственный контроль памяти. Redis указывает, что реплика по умолчанию не обязана применять maxmemory так же, как первичный узел, и может использовать больше памяти из-за буферов и внутренних структур [7]. Проверка только основного экземпляра оставляет риск сбоя во время синхронизации или переключения.

Какие изменения закрепить в коде

  • Создавать кеш вместе со сроком жизни. Запись значения и назначение TTL должны выполняться одной логической операцией, чтобы сбой между двумя командами не оставил бессрочный ключ.
  • Ограничивать растущие структуры. Для журналов, очередей, списков последних действий и счётчиков задают максимальную длину либо явный процесс удаления обработанных элементов.
  • Удалять старые пространства ключей после релиза. Версионирование кеша удобно, но прежний префикс не должен оставаться в памяти навсегда после переключения.
  • Не помещать в кеш объект целиком без необходимости. Иногда дешевле хранить отдельные поля или компактное представление, чем повторять большой сериализованный объект для каждого пользователя.
  • Развести разные классы данных. Кеш, сессии и очередь получают независимые экземпляры или хотя бы отдельные лимиты и наблюдение. Тогда политика вытеснения кеша не затрагивает авторизацию и задания.

После изменения кода проверяют не только исчезновение ошибки. Нужно убедиться, что новые ключи действительно получают TTL, старые записи постепенно уходят, очередь не теряет задания, пользователи не выходят из аккаунтов, а промахи кеша не перегружают основную базу.

Как безопасно проверить исправление

Сначала воспроизводят сценарий на тестовом экземпляре с уменьшенным лимитом: создают типичную нагрузку, доводят память до порога и наблюдают выбранную политику. Для кеша ожидается контролируемое вытеснение; для noeviction — понятная ошибка записи без повреждения уже сохранённых данных. Отдельно проверяют перезапуск, загрузку RDB или AOF и поведение клиента при временном отказе.

На рабочем сервере изменение вводят с наблюдением за памятью, задержкой и бизнес-функциями. До начала сохраняют исходные параметры и способ отката. После переключения проверяют авторизацию, корзину, фоновые задания и страницы, зависящие от кеша. Если менялась политика вытеснения, несколько часов отслеживают не только OOM, но и evicted_keys, hit rate и нагрузку на основную базу.

Когда одного экземпляра Redis уже недостаточно

Разделение требуется не только при нехватке RAM. Если кеш можно удалить и построить заново, а сессии или задания должны пережить перегрузку, у этих данных разные требования к вытеснению, persistence и времени восстановления. Один общий лимит заставляет выбирать компромисс: защищая очередь политикой noeviction, команда рискует остановить запись кеша; разрешая вытеснение всех ключей, она подвергает риску сессии и задания.

Перед разделением составляют карту клиентов Redis: какое приложение подключается, какие префиксы использует, нужна ли ему репликация, допустима ли потеря данных и какое время недоступности приемлемо. Затем переносят один класс данных, меняют строку подключения и проверяют метрики обоих экземпляров. Логические базы с номерами не дают независимых лимитов памяти и политик вытеснения, поэтому для настоящей изоляции нужны отдельные процессы, контейнеры или управляемые базы.

Масштабирование считается завершённым, когда для каждого класса определены владелец, лимит, политика, persistence, резервное копирование и предупреждения. Без этой документации новый общий экземпляр со временем снова превращается в смешанное хранилище и воспроизводит прежний OOM.

Каким должен быть контроль после исправления

Работу можно считать завершённой, когда запись снова проходит, память стабилизируется под реальной нагрузкой, а причина роста устранена. В мониторинг выводят долю used_memory от maxmemory, число вытеснений и отклонённых команд, hit rate, количество ключей и задержку Redis. Предупреждение полезно ставить заранее, чтобы команда увидела тенденцию до остановки записи.

Если OOM повторяется, сравните суточный прирост ключей, TTL и потребление по префиксам. Это быстро отделяет недостаток ёмкости от ошибки приложения. Более общий разбор серверной нагрузки приведён в материале «Как снизить нагрузку на сервер сайта».

Официальные источники

  1. Redis: Key eviction — maxmemory и политики вытеснения.
  2. Redis administration — запас памяти, persistence и рекомендации для сервера.
  3. Redis: Memory optimization — фрагментация и модель потребления памяти.
  4. Redis: Error handling — ресурсные ошибки клиентов, включая OOM.
  5. Redis: INFO — Показатели memory, keyspace, commandstats и errorstats; различие used_memory и RSS..
  6. Redis CLI, SCAN и MEMORY USAGE; дополнительная страница 1; дополнительная страница 2 — Безопасный порционный обход пространства ключей и оценка занимаемой памяти..
  7. Redis replication — Поведение maxmemory и расход памяти на репликах..
  8. Redis: MEMORY STATS и MEMORY DOCTOR; дополнительная страница 1 — Диагностика структуры и проблем потребления памяти..

Быстрые вопросы и ответы

Можно ли просто увеличить maxmemory и перезапустить Redis?

Как временная мера увеличение лимита может вернуть запись, если у сервера есть свободная RAM. До изменения нужно найти причину роста и оставить запас для буферов, persistence и операционной системы, иначе ошибка повторится или процесс завершит OOM killer.

Какая maxmemory-policy подходит для обычного кеша?

Для полностью восстанавливаемого кеша часто используют allkeys-lru или allkeys-lfu. Выбор проверяют по hit rate и характеру доступа. Если Redis хранит сессии, очередь или постоянные данные, политику определяют отдельно для каждого класса.

Почему политика volatile-lru не освобождает память?

Она может вытеснять только ключи с TTL. Если большую часть памяти занимают бессрочные ключи, кандидатов для освобождения не окажется и Redis начнёт отклонять записи. Нужно проверить TTL и назначение таких ключей.

Безопасно ли выполнять FLUSHALL при Redis OOM?

Команда удаляет все ключи во всех логических базах экземпляра. На рабочем сервере это может уничтожить сессии, очереди и данные приложений. Очищают только подтверждённо восстанавливаемый набор по согласованному префиксу и с резервным планом.

Какие метрики предупредят о повторном OOM?

Контролируйте used_memory относительно maxmemory, mem_not_counted_for_evict, свободную RAM узла, evicted_keys, current_eviction_exceeded_time, total_error_replies, INFO errorstats и cmdstat_*.rejected_calls. Дополнительно следите за числом ключей, TTL по префиксам, задержкой и нагрузкой на основную базу после вытеснения кеша.

Как искать крупные ключи на рабочем Redis без KEYS *?

Используйте порционный SCAN, выборочный MEMORY USAGE и режимы анализа redis-cli в период умеренной нагрузки. Результаты группируйте по префиксам, количеству, суммарному размеру и наличию TTL, чтобы найти владельца роста, а не один случайный крупный ключ.

Нужна помощь по этой задаче?
На странице услуги «Устранение Redis OOM и вытеснения ключей» указаны состав работ, результат и фиксированная цена.