← Все статьи

SiteGuard12 мин чтения

Redis удаляет ключи или отвечает OOM: как проверить maxmemory и eviction

Ошибка Redis OOM maxmemory обычно означает отказ конкретной команды из-за ограничения памяти Redis. Пропавший ключ может иметь другую причину: истёкший TTL, удаление приложением, вытеснение или обращение к другому экземпляру. Начните с определения механизма, затем меняйте бюджет памяти и правила хранения.

Для сайта особенно важно назначение данных. Потерянный кеш карточки товара можно построить заново, а исчезнувшая сессия или задание очереди требует отдельной обработки. Политика eviction должна соответствовать допустимости потери. Все числа и имена ключей ниже учебные; команды предназначены для ограниченного чтения диагностической информации.

1. Разделите отказ команды, исчезновение ключа и остановку процесса

Сохраните точный ответ сервера, название команды, время и затронутую функцию сайта. Ошибка OOM при записи не равна отсутствию ответа от Redis. Если процесс завершён операционной системой, нужны журнал ядра и сведения о перезапуске. В рекомендациях по эксплуатации Redis отдельно рассматриваются предел памяти приложения и возможность завершения процесса Linux OOM Killer.

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

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

Запишите версию приложения и изменения перед инцидентом. Новый формат ключей или переключение подключения иногда объясняют «потерю» данных без участия eviction. Такая проверка занимает меньше времени, чем необоснованная смена политики всего экземпляра.

2. Подтвердите экземпляр, роль и логическую базу

Диагностику выполняют через разрешённое подключение к тому серверу, который обслуживает проблемную операцию. Зафиксируйте адрес назначения, версию Redis, роль узла и выбранную базу. В кластере показатели одного узла не описывают весь кластер; после переключения primary адрес подключения может вести уже к другому процессу.

INFO server
INFO replication
INFO memory
INFO stats
INFO keyspace

В разделе server сохраните run_id и uptime_in_seconds вместе со временем измерения. В keyspace посмотрите, какие базы содержат ключи. Сами значения пользовательских сессий для первоначальной проверки не нужны.

В standalone Redis Open Source выбор базы относится к соединению. Согласно документации SELECT, новое соединение начинает работу с DB 0, а Redis Cluster поддерживает только DB 0. Проверяйте настройку приложения и используемого диагностического подключения; не перебирайте базы наугад.

Логические DB разделяют имена ключей, но не предоставляют независимый бюджет памяти процесса. Разнести кеш в DB 0, а сессии в DB 1 недостаточно для защиты сессий от общего ограничения. Если допустимость потери различается, рассматривайте отдельные экземпляры или отдельно управляемые базы сервиса с подтверждёнными независимыми лимитами.

3. Прочитайте фактические maxmemory и maxmemory-policy

Конфигурация в репозитории может отличаться от действующей. При наличии разрешений запросите только нужные параметры:

CONFIG GET maxmemory
CONFIG GET maxmemory-policy

CONFIG GET читает настройки работающего сервера. В управляемом продукте команда или отдельные параметры могут быть ограничены. Тогда используйте доступные показатели INFO и официальную панель поставщика; запрет команды не означает отсутствие лимита.

Значение maxmemory относится к механизму управления памятью Redis, а не к суммарному пределу RAM хоста. Для обычного 64-битного Redis Open Source значение 0 означает отсутствие заданного ограничения набора данных. Оно не отменяет физическую ёмкость, лимит контейнера и ограничения управляемой платформы.

Запишите единицы и действительную область настройки. Если поставщик задаёт память для управляемой базы или шарда, выясните, как этот предел соотносится с показателями узла. Сравнивать лимит одного шарда с суммой по всем узлам нельзя.

Сохраняйте значение политики одновременно с измерениями. Если между двумя снимками её поменяли, изменение числа вытеснений может объясняться настройкой. История конфигурации нужна для вывода о причине, а не только для последующего восстановления параметров.

4. Не приравнивайте used_memory к RSS

В описании INFO used_memory обозначает объём, выделенный аллокатором Redis, а used_memory_rss — резидентную память процесса с точки зрения ОС. Это разные измерения. used_memory_dataset также не заменяет весь расход Redis: кроме полезных значений существуют служебные структуры.

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

Учебный снимок: used_memory равен 2176 MiB, исключённые буферы — 256 MiB, maxmemory — 2048 MiB. Для первичной оценки получается 2176 − 256 = 1920 MiB учитываемого расхода, на 128 MiB ниже лимита. Это не расчёт RSS и не свободная память контейнера.

Сравните также пики и состояние процесса во времени. После удаления ключей RSS не обязан сразу уменьшиться: аллокатор может удерживать освобождённые страницы для повторного использования. Это поведение объясняется в руководстве по памяти Redis. Один высокий коэффициент RSS/used_memory после большого сокращения данных ещё не устанавливает утечку.

5. Проверьте, какие ключи разрешено вытеснять

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

СемействоПоведение при нехватке памяти
allkeys-lru, allkeys-lfuВыбирают кандидатов среди ключей независимо от наличия TTL
volatile-lru, volatile-lfuВыбирают кандидатов только среди ключей с установленным TTL
volatile-ttlПредпочитает кандидатов с более коротким оставшимся TTL
noevictionНе вытесняет ключи по maxmemory; команды, требующие дополнительной памяти, могут получить отказ

Если у volatile-политики нет подходящих ключей с TTL, освобождать память таким способом нечем и запись может завершиться OOM. Наличие этой политики не гарантирует успешное создание новых объектов.

LRU ориентируется на давность использования, LFU — на частоту, причём алгоритмы приближённые. Нельзя обещать, что останется именно выбранный разработчиком ключ. Доступность конкретной политики зависит от версии и продукта; таблица показывает распространённые варианты.

Для кеша выбор оценивают по нагрузке на источник данных после промахов. Для сессий сначала определяют приемлемое поведение при утрате. Для очередей или единственной копии важного состояния нельзя просто включить allkeys-политику ради исчезновения ошибки: восстановленная запись ценой потери заданий меняет смысл работы системы.

Учебный пример: в одном экземпляре кеш записывается без TTL, а сессии получают срок жизни. При volatile-lru кандидатами окажутся именно сессии, хотя владелец рассчитывал освобождать кеш. Префикс имени не меняет правила отбора. Перед изменением политики составьте перечень типов данных и фактического наличия TTL, затем проверьте, совпадает ли круг кандидатов с тем, что бизнес разрешает терять.

6. Отличите TTL, явное удаление и eviction

Проверяйте заранее известный ключ в подтверждённой базе. Например:

TTL session:demo:42
TYPE session:demo:42

TTL возвращает оставшееся время в секундах; в современных версиях −1 означает существующий ключ без срока, а −2 — отсутствие ключа. TYPE позволяет сверить тип значения с ожиданием приложения. Эти команды не возвращают содержимое сессии.

TTL −2 не объясняет причину отсутствия. Ключ мог истечь, быть удалён командой приложения, вытеснен или вообще не создан. Два последовательных чтения не являются атомарным снимком: между ними другой клиент может удалить или пересоздать объект.

Политика noeviction не отключает истечение срока. В описании механизма expiration объясняется удаление просроченных ключей при обращениях и фоновой проверке. Поэтому сессия с заданным временем жизни исчезнет по сроку даже при запрете вытеснения по памяти.

Свяжите наблюдение с жизненным циклом ключа: кто создаёт его, задаёт TTL, продлевает срок и удаляет при выходе пользователя. Рост evicted_keys помогает подтвердить вытеснения на экземпляре, но не устанавливает, что конкретная сессия исчезла именно так. Для этого нужны дополнительные сведения приложения о данном ключе и времени.

7. Сравните счётчики за один интервал

В INFO stats evicted_keys относится к вытеснениям из-за maxmemory, expired_keys — к истечениям срока, keyspace_hits и keyspace_misses — к успешным и неуспешным поискам ключей. Это накопленные показатели; их большое абсолютное значение само по себе не описывает текущий инцидент.

Допустим, за учебные пять минут на одном экземпляре evicted_keys вырос с 900 до 1500, а expired_keys — с 2000 до 2300. Получены 600 вытеснений и 300 истечений. Это разные события, их не следует объединять в «900 ошибок». Для кеша часть таких событий может быть ожидаемой.

В том же окне hits увеличились со 100 000 до 106 000, misses — с 20 000 до 22 000. Доля успешных поисков за интервал равна 6000 / (6000 + 2000) = 75%. Расчёт по итоговым накопленным значениям дал бы примерно 82,8% и скрывал бы изменение последних минут.

Этот процент не является долей успешных покупок или универсальным показателем здоровья сайта. Одна пользовательская операция обращается к нескольким ключам, а статистика может смешивать кеш и сессии. Интерпретируйте её вместе с поведением приложения.

При смене run_id, перезапуске, переключении узла или уменьшении счётчиков начните новое окно. Не вычитайте показатели разных процессов. Сохраняйте время, идентичность экземпляра и действовавшую политику рядом с каждым снимком.

8. Найдите, какие данные расходуют память

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

MEMORY USAGE cache:demo:product:42 SAMPLES 5

По документации MEMORY USAGE, результат включает память данных и служебные расходы ключа. Для вложенных структур используются выборки; это оценка. Увеличение обследуемого объёма повышает стоимость диагностики, поэтому начинайте с нескольких характерных объектов.

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

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

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

9. Оставьте запас сверх maxmemory

Рассмотрим учебный отдельный сервер с 4 GiB RAM, то есть 4096 MiB. Для заданной тестовой нагрузки команда оценила следующие непересекающиеся части бюджета:

Статья расхода или резерваОбъём
Планируемый maxmemory2048 MiB
Пик исключённых буферов256 MiB
Дополнительный resident-расход сверх учтённых выделений384 MiB
Дополнительные страницы copy-on-write512 MiB
ОС и остальные процессы512 MiB

Сумма равна 3712 MiB, остаток — 384 MiB. Если повысить только maxmemory до 2560 MiB, оценка вырастет до 4224 MiB и превысит ёмкость на 128 MiB. Прибавка к лимиту устраняет один барьер, но создаёт риск для всего процесса.

Резерв copy-on-write здесь получен для учебного профиля записей, а не установлен как универсальная норма. Сохранение снимка и переписывание AOF могут потребовать дополнительной памяти; при другой интенсивности изменений запас пересчитывают. Не складывайте весь RSS с used_memory: иначе одни и те же данные будут учтены дважды.

Одна большая команда способна временно превысить maxmemory. Кроме того, ограничения контейнера могут оказаться ниже физической RAM хоста. Проверяйте бюджет одновременно на уровне Redis, контейнера и сервера, включая фоновые операции. Указанный лимит не является жёсткой гарантией верхней границы RSS.

В этой модели дополнительный resident-расход не является всем RSS, а copy-on-write учитывается как дополнительные физические страницы, без повторного включения общих страниц родителя и дочернего процесса. Каждый резерв требует своего измерения. Если пики буферов и фонового сохранения могут совпасть, их совместное потребление проверяют специально; усреднённые значения за разные часы не гарантируют достаточного запаса.

10. Исправьте причину вместе с владельцем данных

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

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

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

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

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

11. Не рассчитывайте на автоматическое возвращение ключей

RDB и AOF предназначены для сохранения состояния и восстановления после остановки в рамках выбранной схемы. Они не являются автоматической корзиной для каждого вытесненного ключа. Удаления и истечения могут уже отражаться в сохранённом состоянии.

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

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

Если единственной копии больше нет, повышение maxmemory её не воссоздаст. В отчёте разделите восстановление возможности новых записей, восстановление пользовательской функции и установленные потери данных. Так техническое улучшение не будет ошибочно представлено как полное восстановление информации.

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

12. Подтвердите результат на характерной нагрузке

В тестовом окружении повторите ожидаемые размеры данных и параллельность запросов. Проверяйте успешность записи, прирост счётчиков, пики памяти, работу фонового сохранения и нагрузку на источник кеша. Для noeviction важен сценарий контролируемого отказа; для кеша с eviction — корректное восстановление отсутствующего значения.

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

Подключите SiteGuard для внешнего контроля HTTP-доступности важных страниц. Состояние Redis, память и сохранность ключей проверяйте средствами приложения и инфраструктуры.