Привет, Хабр! На связи Александр Горьев, ведущий разработчик в Selectel. Redis — это высокопроизводительное хранилище «ключ-значение», работающее в оперативной памяти. Скорость, простота и богатый набор структур сделали Redis столь популярным. Кеширование HTTP-ответов, хранение сессий, реализация очередей задач, счетчиков, лидербордов и ограничения запросов (rate limiting) — далеко не полный перечень вариантов его применения.

На старте Redis часто воспринимается как инструмент, который отлично работает «из коробки». Действительно, при небольшом объеме данных и малом числе клиентов он стабильно быстр даже с настройками по умолчанию. Однако с ростом нагрузки и усложнением архитектуры появляются проблемы:

  • исчерпание памяти,

  • неожиданные сбросы данных,

  • увеличение задержек (latency),

  • различные сбои в работе сервиса.

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

Легкость первоначального внедрения создает своего рода «ловушку компетентности». Разработчики успешно применяют Redis для простых задач. Затем они начинают ошибочно полагать, что и эффективно масштабироваться он будет так же — без дополнительного вмешательства. Настоящий же вызов не в том, чтобы начать использовать Redis, а в том, чтобы грамотно сопровождать его рост.

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

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

Используйте навигацию, если не хотите читать текст целиком:

Управление памятью: первый шаг к стабильности

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

Для ограничения и контроля использования памяти в Redis есть два ключевых параметра:

  • maxmemory задает максимальный объем RAM для пользовательских данных; при достижении лимита Redis применит политику вытеснения ключей, чтобы освободить место для новых записей;

  • maxmemory-policy определяет алгоритм вытеснения ключей при нехватке памяти.

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

Политики вытеснения ключей разнообразны. Рассмотрим самые практичные стратегии.

allkeys-lru — вытеснение давно неиспользуемых данных

Redis удаляет ключи, к которым дольше всего не было обращений (Least Recently Used). Устаревшие данные освобождают место для актуальной информации.

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

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

allkeys-lfu — вытеснение редко используемых данных

Удаляются ключи, которые требуются эпизодически (Least Frequently Used), даже если к ним обращались совсем недавно. Политика сохраняет данные, востребованные в долгосрочной перспективе.

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

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

volatile-ttl — вытеснение отработанных данных

Redis начнет вытеснение с ключей, у которых наименьшее значение времени жизни (TTL, Time To Live).

Такая политика идеальна для сценариев, где в одном экземпляре Redis смешаны и временные (кеш), и постоянные (критичные) данные. Важная информация с неустановленным TTL защищена от вытеснения.

Пример. Вы храните данные двух видов:

  • временные сессии пользователей — TTL, скажем, пять минут;

  • постоянные настройки приложения — TTL не установлен.

При нехватке памяти критически важные настройки не будут затронуты. Уйдут уже устаревшие сессии, которые наверняка останутся невостребованными.

noeviction — запрет на вытеснение данных

Redis не удаляет ключи при достижении лимита maxmemory. При этом будут завершаться ошибкой все команды записи, требующие новой памяти — например, SET или LPUSH. Команды чтения продолжат работать.

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

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

Полный список политик и включение их в панели управления описаны в нашей документации. Смотрите также официальную страницу Key eviction от разработчиков Redis.

Стоит отметить, что алгоритмы LRU и LFU в Redis — это алгоритмы аппроксимации. Для экономии ресурсов Redis не сканирует все ключи, а анализирует небольшую случайную выборку. Количество элементов задает параметр maxmemory-samples. Так, при определении кандидата на вытеснение обеспечивается отличный баланс между точностью и производительностью.

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

Подробнее →

Оптимизация клиентских подключений: контроль за сетевыми ресурсами

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

Даже при правильно настроенном maxmemory, Redis может испытывать проблемы из-за множества открытых, но неиспользуемых TCP-соединений. Каждое из них потребляет память и требует файловый дескриптор на сервере. В итоге исчерпается лимит maxclients и утратится возможность принимать новые подключения.

Проблема особенно актуальна для современных архитектур — микросервисов или бессерверных вычислений (FaaS). Там тысячи эфемерных клиентов могут часто подключаться и отключаться. Если даже малая часть из них не закроет соединение корректно, число таких «зомби» будет неуклонно расти и в какой‑то момент застопорит Redis.

Для борьбы с этим явлением есть два ключевых параметра.

timeout — задает время в секундах, по истечении которого сервер закроет неактивное соединение. Параметр работает на уровне приложения Redis. По умолчанию его значение — 0, то есть бесконечное ожидание. В продакшн‑средах оставлять такую установку крайне опасно. Рекомендуется ограничиться разумной продолжительностью — скажем, 300 секунд — для автоматической очистки ресурсов от «забытых» клиентов.

tcp-keepalive — работает на более низком, сетевом уровне операционной системы (опция сокета SO_KEEPALIVE). Он позволяет обнаруживать «мертвые» Idle‑соединения.  Типичный пример: клиент оборвал связь из-за сбоя, а сервер об этом не узнал. ОС периодически проверяет подключение, передавая ACK‑запрос. Если ответа нет, соединение принудительно закрывается. В современных версиях Redis параметр по умолчанию установлен и имеет значение около 300 секунд — безопасная и разумная настройка.

Грамотный подбор параметров особенно важен в распределенных системах и при работе через прокси, где соединения могут неожиданно разрываться или «зависать». Подытожим:

  • timeout защищает от бездействующих, но корректно работающих клиентов;

  • tcp-keepalive — от неработающих клиентов и сбоев на уровне сети.

Оба механизма защищают от исчерпания ресурсов подключений.

Надежность: стратегии персистентности RDB и AOF

Как бы хорошо ни были настроены ограничения по памяти и клиентским соединениям, Redis остается RAM‑хранилищем. При перезапуске процесса или сбое хоста все несохраненные на диск данные утрачиваются безвозвратно. Механизмы персистентности позволяют избежать потери информации, которая не должна исчезнуть. Для этого Redis предлагает два основных подхода — RDB и AOF, каждый из которых предпочтителен для разных сценариев.

Redis Database Backup (RDB)

RDB-персистентность создает снимки (snapshots) всей базы данных в определенные моменты времени — это эффективно при небольших объемах и редко изменяющихся структурах.

Инициатором выступает фоновый процесс bgsave, который создается через системный вызов fork(). Дочерний процесс получает копию данных и записывает ее на диск. В это время родительский процесс продолжает обслуживать клиентов — влияние на производительность минимальное.

За настройку RDB отвечает опция save. Например, можно выставить следующие значения:

save 3600 1
save 300 100
save 60 10000

Правила выше означают, что Redis автоматически создаст снимок, если:

  • за час произошло как хотя бы одно изменение,

  • в течение пяти минут — не менее 100 изменений,

  • в минуту — 10 000 изменений и больше.

Для полного отключения автоматического сохранения RDB используется пустая директива:

save ""

Преимущество RDB — это компактные файлы, идеально подходящие для резервного копирования и аварийного восстановления. Все очень быстро — всего один бинарный файл для записи. Влияние на производительность основного процесса — минимальное.

Недостатки RDB — возможна потеря данных: при сбое будут утеряны все изменения с момента последнего снимка.

Append Only File (AOF)

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

Такой подход хорош для сценариев, где требуется минимальная потеря данных.

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

appendfsync определяет, как часто данные из буфера записываются на диск. Есть несколько возможных значений.

  • always — максимальная надежность, так как данные сохраняются на диск после каждой новой строки в AOF‑файле. Однако такой режим существенно замедляет работу Redis, так как тот каждый раз ждет завершения операции fsync().

  • everysec — компромисс между скоростью и надежностью. Как видно из названия, данные записываются каждую секунду. Опция включена по умолчанию и подходит для большинства сценариев.

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

  • auto-aof-rewrite-percentage и auto-aof-rewrite-min-size управляют автоматической перезаписью лога и позволяют контролировать требуемый объем на диске. Со временем  AOF‑файл может сильно разрастаться, но когда его размер превышает auto-aof-rewrite-min-size на заданный процент auto-aof-rewrite-percentage, Redis создает новый, компактный AOF-файл, который содержит минимальный набор команд.

Преимущество AOF состоит в гораздо более высокой надежности — например, при использовании everysec риск потери данных минимален. Лог-файл легко читаем и восстанавливается даже при частичном повреждении.

Недостаток AOF в большем размере файлов по сравнению с RDB‑снимками. Восстановление происходит медленнее, что особенно чувствуется на больших наборах.

Сравнительный анализ и гибридный подход

Начиная с Redis 4.0, доступен гибридный режим. При перезаписи AOF-файла Redis может в начало лога поместить RDB-снимок, а после него — команды, поступившие во время создания снимка. Сочетаются преимущества обоих подходов: быстрое восстановление RDB и высокая надежность AOF.

В таблице ниже приведено краткое сравнение двух подходов.

Характеристика

RDB (Snapshot)

AOF (Append Only File)

Что сохраняется

Полный снимок данных на конкретный момент времени

Каждая команда, изменяющая данные

Формат хранения

Бинарный snapshot-файл

Журнал команд в текстовом виде

Частота обновлений

По расписанию (определяется параметрами save)

Зависит от appendfsync (каждую секунду, всегда или управление передано ОС)

Скорость восстановления

Быстрая, загружается один файл

Медленнее, происходит воспроизведение всех команд

Надежность

Возможна потеря данных между снимками

Высокая, можно восстановить почти все изменения

Размер файла

Компактный

Может расти быстро без перезаписи

Типичные сценарии

Быстрый бэкап

Высокая устойчивость, критичные данные

Выбор между RDB, AOF или их комбинацией зависит от требований конкретного приложения к долговечности данных и допустимому времени простоя.

Эффективность на уровне данных: выбор правильных структур

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

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

Более подробно о типах данных можно узнать в документации.

В рамках статьи мы рассмотрим только некоторые из них, а также выделим их особенности.

String — базовая структура, последовательность байт. Однако, несмотря на свою простоту, внутри она реализована не как чистая строка, а как комплексный объект с дополнительными служебными полями:

  • тип значения,

  • референс-счетчик,

  • флаги,

  • метки,

  • структура с метаинформацией — длиной, выделенным буфером и др.

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

Hash — используется для хранения связанных пар значений. Строение аналогично словарю, однако реализация возможна двумя способами: listpack и hashtable.

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

user:1001:name -> "John Doe"
user:1001:email -> "john.doe@example.com"
user:1001:visits -> 150

Видно, что для одного пользователя создаются три отдельных ключа, каждый со своими накладными расходами. Гораздо лучше взять структуру Hash:

user:1001 -> { "name": "John Doe", "email": "john.doe@example.com", "visits": "150" }

Используется всего один ключ верхнего уровня, а все поля хранятся внутри него. Секрет эффективности кроется в кодировании небольших хешей. Пока количество полей в хеше и размер их значений не превышают порогов, задаваемых параметрами hash-max-listpack-entries и hash-max-listpack-value, Redis использует не полноценную хеш-таблицу, а специальную, чрезвычайно компактную структуру listpack.

В более ранних версиях вместо listpack использовалась структура ziplist, а ее параметры назывались соответственно hash-max-ziplist-entries и hash-max-ziplist-value.

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

listpack — это, по сути, плоский массив байт, который хранит данные последовательно. У него, в отличие от обычных хеш‑таблиц, нет накладных расходов на указатели и метаданные. Использование listpack может сократить потребление памяти в 5−10 раз по сравнению с хранением тех же данных в виде отдельных String‑ключей. Если же хеш вырастает и превышает лимиты, Redis автоматически и прозрачно для пользователя преобразует его в стандартную hashtable — более затратную по памяти, но быструю на больших объемах.

Такая оптимизация имеет и прямые финансовые последствия. Сокращение потребления памяти в несколько раз означает, что компания может:

  • обрабатывать во столько же раз больше данных на том же оборудовании;

  • использовать значительно меньшие, а значит, и более дешевые инстансы Redis.

И в том, и в другом случае операционные расходы (OpEx) снижаются напрямую.

Базовая рекомендация: если вы храните связанные поля для множества однотипных объектов, всегда отдавайте предпочтение структуре Hash перед набором String‑ключей и экспериментируйте с параметрами hash-max-listpack-entries и hash-max-listpack-value.

Модули: расширение возможностей Redis

Встроенных структур данных и команд Redis часто бывает достаточно. Однако в проектах со сложной бизнес-логикой возникают задачи, которые Redis «из коробки» не решит. Примерами могут послужить: необходимость в полнотекстовом поиске, работа с вложенными JSON-объектами или аналитика временны́х рядов.

В таких случаях на помощь приходят модули. Они добавляют команды и новые типы данных, превращая Redis в многомодельную БД. Благодаря им удается избежать «зоопарка технологий», когда для разных задач приходится поддерживать несколько систем хранения — например, Redis для кеша, Elasticsearch для поиска, MongoDB для документов. Архитектура значительно упрощается, а значит, и снижается операционная сложность.

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

Модуль

Назначение

Примеры

Примечания

RedisJSON

Работа с JSON-документами как с нативным типом данных, поддержка атомарных операций над полями

Хранение профилей пользователей, каталогов товаров, конфигураций

Не каждый облачный провайдер поддерживает. Требуется продуманное проектирование схемы JSON

RediSearch

Полнотекстовый поиск, сложная фильтрация и агрегация по индексированным данным

Поиск по сайту, фильтрация товаров по множеству атрибутов

Может потреблять значительные ресурсы CPU и памяти. Не является полной заменой специализированным поисковым движкам для всех сценариев

RedisBloom

Вероятностные структуры данных: фильтр Блума, фильтр Куку, Count-Min Sketch

Детектор уникальности — например, для предотвращения повторного показа рекламы, подсчет частоты событий

Структуры являются вероятностными, возможны ложноположительные срабатывания. Не подходят для задач, требующих 100% точности

RedisTimeSeries

Эффективное хранение, агрегация и запросы к временны́м рядам

Мониторинг системных метрик, сбор данных с IoT-устройств, финансовые данные

Оптимизирован именно для временных рядов, не для хранения данных общего назначения

RedisGraph

Работа с графовыми данными и связями между объектами с использованием языка запросов Cypher

Анализ социальных сетей, построение систем рекомендаций, обнаружение мошенничества

Требует знаний в области графовых баз данных и языка Cypher. Относительно нишевый сценарий использования

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

Мониторинг и бенчмарки: как измерить производительность

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

redis-benchmark – нагрузочное тестирование

redis-benchmark — это CLI‑утилита из стандартной поставки Redis. Она эмулирует параллельную работу множества клиентов и выполняет типовые Redis-команды с заданным профилем нагрузки. Это удобный инструмент для проактивного тестирования, который позволяет оценить пропускную способность и устойчивость сервера: «Как тот справится с ожидаемой нагрузкой?» или «Как изменение конфигурации повлияет на производительность?».

Пример запуска: 

redis-benchmark -c 50 -n 100000

Здесь:

  • -c 50 — число одновременных клиентских подключений,

  • -n 100000 — общее количество запросов для выполнения.

Такой тест позволяет выявить, как Redis справляется с массовыми запросами, насколько стабильно распределяется нагрузка и где возможные узкие места.

latency — мониторинг задержек

Этот инструмент предназначен для диагностики эпизодических задержек в реальном времени. Он отслеживает не только продолжительность выполнения команд, но и задержки, вызванные системными событиями — например, медленным fork() или проблемами с сетью. С его помощью можно найти ответ на вопрос: «Почему сервер иногда работает медленно?».

По умолчанию монитор отключен. Для его активации нужно задать порог в миллисекундах:

CONFIG SET latency-monitor-threshold 100

Команда выше зафиксирует все события, которые длились более 100 мс.

Для анализа доступны следующие опции:

  • LATENCY LATEST — показывает последние события с превышением порога;

  • LATENCY HISTORY <название команды> — отображает историю превышений для конкретной команды;

  • LATENCY DOCTOR — агрегирует данные о задержках и предлагает человекочитаемые рекомендации по устранению их причин.

slowlog — анализ медленных команд

Если LATENCY указывает на системные проблемы, то SLOWLOG помогает найти неэффективные команды на уровне приложения. Он отвечает на вопрос: «Какие конкретные запросы от приложения влияют на производительность?».

Лог медленных команд по умолчанию фиксирует запросы, выполняющиеся дольше значения параметра slowlog-log-slower-than (в микросекундах). Для повышения чувствительности можно уменьшить этот порог:

CONFIG SET slowlog-log-slower-than 10000

Команда выше установит порог в 10 мс.

Для просмотра лога используется команда: 

SLOWLOG GET

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

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

Заключение: системный подход к здоровью Redis

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

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

В этой статье мы рассмотрели ключевые направления оптимизации:

  • стратегическое управление памятью через maxmemory и осознанный выбор политики вытеснения;

  • проактивный контроль клиентских подключений с помощью timeout и tcp-keepalive для предотвращения исчерпания ресурсов;

  • информированный выбор стратегии персистентности — RDB, AOF или гибридный подход, — балансирующей между надежностью и производительностью;

  • интеллектуальное моделирование данных на уровне приложения — в частности, использование Hash вместо множества String ключей для колоссальной экономии памяти;

  • непрерывный мониторинг и диагностика с помощью встроенных инструментов для своевременного обнаружения и устранения узких мест.

Понимание этих аспектов не только повысить производительность, но и сделает работу Redis предсказуемой и устойчивой.

Комментарии (3)


  1. WhiteApfel
    29.07.2025 15:10

    Пришёл в комментарии написать "Уже писали про dragonfly?", а тут пусто...


  1. olku
    29.07.2025 15:10

    RedisTimeSeries заслуживает отдельной статьи. Реализация downsampling в нем потрясающая.


  1. diderevyagin
    29.07.2025 15:10

    Хорошая статья. Можно еще попробовать сделать что-то вроде "как убить производительность", описав набор антипаттернов ... те-же keys некоторые до сих пор любят