OOM command not allowed when used memory > maxmemory: как исправить ошибку Redis
Содержание 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 одновременно обслуживает кеш, сессии и очередь, безопаснее разделить нагрузки по разным базам или экземплярам с независимыми лимитами.
Как восстановить запись без опасных действий
- Остановите источник неконтролируемого роста. Это может быть зависшая очередь, ключ без TTL, массовый импорт или новый релиз.
- Удалите только подтверждённо восстанавливаемые данные. Перед очисткой проверьте префикс, владельца и способ повторного построения.
FLUSHALLдля общей рабочей базы почти всегда слишком груб. - Верните срок жизни новым ключам. Исправление должно появиться в коде, иначе ручная очистка лишь переносит следующий OOM.
- Выберите политику вытеснения по смыслу данных. Для чистого кеша часто подходят
allkeys-lruилиallkeys-lfu. Для смешанной базы решение принимают после разделения классов ключей. - Изменяйте лимит с запасом для процесса и ОС. Redis рекомендует учитывать служебные буферы и пиковое потребление [2].
- Закрепите конфигурацию. Изменение через
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 и потребление по префиксам. Это быстро отделяет недостаток ёмкости от ошибки приложения. Более общий разбор серверной нагрузки приведён в материале «Как снизить нагрузку на сервер сайта».
Официальные источники
- Redis: Key eviction — maxmemory и политики вытеснения.
- Redis administration — запас памяти, persistence и рекомендации для сервера.
- Redis: Memory optimization — фрагментация и модель потребления памяти.
- Redis: Error handling — ресурсные ошибки клиентов, включая OOM.
- Redis: INFO — Показатели memory, keyspace, commandstats и errorstats; различие used_memory и RSS..
- Redis CLI, SCAN и MEMORY USAGE; дополнительная страница 1; дополнительная страница 2 — Безопасный порционный обход пространства ключей и оценка занимаемой памяти..
- Redis replication — Поведение maxmemory и расход памяти на репликах..
- Redis: MEMORY STATS и MEMORY DOCTOR; дополнительная страница 1 — Диагностика структуры и проблем потребления памяти..