Новинка Виртуальный VDS сервер в Нидерландах от 490р
Выберите продукт

Redis на VDS: maxmemory, eviction policy, RDB/AOF и лимиты systemd

Redis на VDS легко довести до OOM: maxmemory ограничивает не весь RSS, eviction влияет на ошибки приложения, а RDB/AOF требуют запаса RAM и диска. Разберём безопасную настройку и проверки перед нагрузкой.
Redis на VDS: maxmemory, eviction policy, RDB/AOF и лимиты systemd

Redis часто ставят на VDS как кэш, хранилище сессий, брокер простых очередей или быстрый слой для счётчиков. Он действительно быстрый, но за скорость приходится платить вниманием к памяти, диску и лимитам сервиса. Самая типичная ошибка — установить Redis, оставить настройки по умолчанию и вспомнить о них только после внезапного OOM, зависшего AOF rewrite или лавины ошибок OOM command not allowed в приложении.

В этой инструкции разберём практическую настройку Redis на VDS: как выбрать maxmemory, какую eviction policy использовать под разные сценарии, когда включать RDB, AOF или оба механизма, а также какие systemd limits проверить, чтобы Redis не упёрся в лимит файлов, cgroup-памяти или слишком жёсткий unit.

Главная мысль: maxmemory — это не вся память процесса Redis, а ограничение на набор данных и часть внутренних структур. На VDS всегда нужен запас для ОС, клиентов, fork при сохранении, файловой системы и соседних сервисов.

Что именно потребляет память в Redis

Redis хранит данные в памяти, но его RSS почти всегда больше «полезного» объёма ключей. В расход входят сами значения, имена ключей, служебные структуры, allocator overhead, буферы клиентов, репликационный backlog, Lua/functions, временные структуры при операциях над большими коллекциями и copy-on-write при фоновых сохранениях.

Например, если в Redis лежит 1 ГБ данных по показателю used_memory, это не означает, что процессу хватит ровно 1 ГБ RAM. Во время BGSAVE или BGREWRITEAOF Redis делает fork. Дочерний процесс сохраняет данные на диск, а родитель продолжает обслуживать запросы. Если приложение активно меняет ключи, ядро начинает копировать изменяемые страницы памяти. На практике это может добавить сотни мегабайт или даже гигабайты RSS на загруженном сервере.

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

Быстрая диагностика текущего состояния

Перед изменением конфигурации посмотрите, как Redis живёт сейчас. Начните с версии, роли, памяти и статистики вытеснения:

redis-cli INFO server
redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO persistence
redis-cli CONFIG GET maxmemory
redis-cli CONFIG GET maxmemory-policy

Особенно полезны поля used_memory, used_memory_rss, used_memory_peak, mem_fragmentation_ratio, maxmemory, evicted_keys, expired_keys, keyspace_hits, keyspace_misses, rdb_last_bgsave_status, aof_last_bgrewrite_status и latest_fork_usec.

redis-cli MEMORY STATS
redis-cli MEMORY DOCTOR
redis-cli SLOWLOG GET 10
redis-cli LATENCY DOCTOR

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

Как рассчитать безопасный maxmemory для VDS

Универсальной цифры нет: Redis может быть единственным сервисом на VDS или жить рядом с Nginx, PHP-FPM, PostgreSQL/MySQL, очередями и агентами мониторинга. Рабочий подход такой: сначала резервируем память под систему и соседние процессы, затем закладываем запас на fork и буферы Redis, и только остаток отдаём под maxmemory.

Для VDS с 2 ГБ RAM, где кроме Redis работают Nginx и приложение, я бы не начинал с maxmemory 1800mb. Более безопасный старт — 768 МБ или 1024 МБ, затем наблюдение за пиками. Для VDS с 4 ГБ RAM, где Redis — основной сервис, часто разумно начать с 2–2.5 ГБ, оставив запас под fork, page cache, сеть и служебные процессы.

Грубая формула для одиночного Redis на VDS выглядит так:

maxmemory = RAM - OS reserve - other services - fork reserve - safety margin

fork reserve зависит от записи. Если Redis почти read-only и редко меняет ключи, запас может быть меньше. Если это сессии, rate limit, очереди или горячий кэш с постоянной перезаписью, запас нужен больше. На маленьких серверах лучше перестраховаться: падение Redis из-за OOM обычно дороже, чем недоиспользованные 200–500 МБ.

Схема расчёта безопасного maxmemory для Redis на VDS

Где настраивать Redis в разных системах

В большинстве Linux-дистрибутивов основной файл называется redis.conf, но имя systemd-сервиса может отличаться. Ниже — практичные ориентиры для популярных вариантов.

Debian и Ubuntu

sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.bak.$(date +%F)
sudo grep -E '^(maxmemory|maxmemory-policy|save|appendonly|appendfsync)' /etc/redis/redis.conf
sudo systemctl status redis-server

После правки конфигурации перезапустите сервис и проверьте журнал:

sudo systemctl restart redis-server
sudo systemctl status redis-server
redis-cli PING
sudo journalctl -u redis-server -n 100 --no-pager

RHEL-based: AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux, Fedora

В этих системах сервис чаще называется redis. Путь к конфигурации обычно тот же, но его лучше проверить через systemd unit.

sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.bak.$(date +%F)
sudo systemctl cat redis
sudo systemctl status redis
sudo grep -E '^(maxmemory|maxmemory-policy|save|appendonly|appendfsync)' /etc/redis/redis.conf

Перезапуск и проверка:

sudo systemctl restart redis
sudo systemctl status redis
redis-cli PING
sudo journalctl -u redis -n 100 --no-pager

FreeBSD

На FreeBSD Redis встречается реже в типовых веб-стеках на VDS, но если вы используете именно его, важны другие пути и rc-сервис.

sudo cp /usr/local/etc/redis.conf /usr/local/etc/redis.conf.bak.$(date +%F)
sudo service redis status
sudo service redis restart
redis-cli PING
FastFox VDS
Облачный VDS-сервер
Виртуальные серверы с быстрым запуском и гибкой конфигурацией от 390₽ / мес
Доступные локации
Россия Нидерланды

Настройка maxmemory

Минимальный набор параметров для Redis как кэша выглядит так:

maxmemory 1024mb
maxmemory-policy allkeys-lfu

Для Redis как хранилища, где потеря ключей недопустима, подход другой:

maxmemory 1024mb
maxmemory-policy noeviction

После изменения файла перезапустите сервис и убедитесь, что Redis видит новые значения:

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

Можно менять параметры через CONFIG SET, но для постоянной настройки лучше править конфигурационный файл или использовать CONFIG REWRITE осознанно. В production я предпочитаю хранить изменения в конфиге и в системе управления конфигурацией: так проще восстановить сервер и понять историю правок.

redis-cli CONFIG SET maxmemory 1024mb
redis-cli CONFIG SET maxmemory-policy allkeys-lfu

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

Как выбрать eviction policy

eviction policy определяет, что Redis будет делать, когда достигнет maxmemory. Ошибка выбора здесь напрямую отражается на приложении: где-то лучше вытеснить старый кэш, а где-то лучше вернуть ошибку записи, чем незаметно удалить важную сессию или задачу.

  • noeviction — не удалять ключи, а возвращать ошибку на команды, которые требуют дополнительной памяти. Подходит для данных, которые нельзя терять автоматически.
  • allkeys-lru — вытеснять наименее недавно использованные ключи из всего набора. Хороший классический вариант для кэша.
  • allkeys-lfu — вытеснять редко используемые ключи из всего набора. Часто лучше для кэша с устойчивыми «горячими» объектами.
  • volatile-lru и volatile-lfu — вытеснять только ключи с TTL. Подходит, если вы строго отделяете временные ключи от постоянных.
  • volatile-ttl — вытеснять ключи с ближайшим истечением TTL. Может быть полезно для некоторых сессионных сценариев, но не является универсальным выбором.
  • allkeys-random и volatile-random — случайное вытеснение. Простые, но обычно менее предсказуемые.

Для Redis как обычного кэша сайта или API я чаще начинаю с allkeys-lfu или allkeys-lru. Для объектного кэша CMS, кэша результатов запросов, фрагментов страниц и похожих данных вытеснение нормально: приложение сможет пересчитать значение или сходить в базу. Если выбираете между Redis и Memcached для PHP-приложения, пригодится отдельный разбор про Memcached и Redis для PHP-кэша.

Для сессий всё тоньше. Если потеря сессии приводит только к повторной авторизации, можно использовать TTL и аккуратную volatile-политику. Если сессии критичны, лучше не смешивать их с агрессивным кэшем в одном Redis. Хорошая практика — отдельный инстанс Redis или хотя бы отдельная база и строгая дисциплина TTL, но помните: eviction policy применяется ко всему инстансу, а не к отдельной базе. Для PHP есть важные нюансы блокировок, о них подробнее написано в статье про PHP session locking и Redis.

Для очередей, idempotency keys, rate-limit состояний и временных блокировок важно понимать последствия. Удалённый ключ rate limit может ослабить ограничение, удалённая задача может сломать обработку, а удалённый lock — привести к гонкам. В таких сценариях noeviction и явная обработка ошибок часто безопаснее, чем «магическое» вытеснение.

Если в одном Redis живут и кэш, и важные данные, вы почти наверняка рано или поздно выберете eviction policy, которая вредна для одной из задач. Разделяйте роли, если бюджет VDS позволяет.

TTL: без него eviction превращается в лотерею

Даже при allkeys-lru или allkeys-lfu полезно задавать TTL на кэшируемые значения. TTL делает поведение понятнее, ограничивает накопление мусора и помогает приложению естественно обновлять данные. Для volatile-политик TTL обязателен: Redis будет вытеснять только ключи с установленным сроком жизни, а ключи без TTL останутся неприкосновенными.

Проверьте долю ключей с истечением в каждой базе:

redis-cli INFO keyspace

Пример вывода может выглядеть так: db0:keys=120000,expires=90000,avg_ttl=3600000. Если вы рассчитываете на volatile-lru, а expires близок к нулю, при достижении лимита Redis будет вести себя не так, как вы ожидали: вытеснять почти нечего, и приложение начнёт получать ошибки.

RDB: снимки Redis и их цена

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

Типичный фрагмент конфигурации:

save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /var/lib/redis
stop-writes-on-bgsave-error yes

Эти строки означают: сделать снимок, если за 900 секунд была хотя бы одна запись, за 300 секунд — 10 записей, за 60 секунд — 10000 записей. Чем активнее запись и чем больше dataset, тем внимательнее нужно относиться к fork и диску.

На VDS с ограниченным I/O слишком частые RDB-снимки могут давать пики задержек. Если приложение чувствительно к latency, смотрите latest_fork_usec, rdb_last_bgsave_time_sec, системный iostat и задержки Redis. Если снимок занимает десятки секунд и совпадает с пиками записи, возможно, стоит ослабить расписание RDB или перейти к комбинации с AOF.

Схема работы RDB и AOF в Redis с сохранением данных на диск

AOF: журнал операций и fsync

AOF сохраняет команды записи в append-only файл. Это обычно даёт меньший RPO, чем один RDB: при режиме appendfsync everysec в типичном случае можно потерять около секунды записей. Но AOF активнее использует диск, а периодический rewrite также требует fork и временного места.

Базовая production-настройка для многих веб-проектов:

appendonly yes
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

appendfsync always максимально осторожен к потере данных, но часто слишком дорог по задержкам и I/O для обычного VDS. appendfsync no быстрее, но отдаёт решение о сбросе данных ядру ОС, что увеличивает потенциальную потерю при аварии. Компромисс everysec обычно самый практичный.

Начиная с Redis 7, AOF хранится в multi-part формате: базовый файл и инкрементальные файлы управляются через manifest. Это нормальное поведение. Не удаляйте отдельные AOF-файлы вручную, если не понимаете структуру каталога. Для диагностики используйте redis-check-aof, а для резервного копирования учитывайте весь каталог AOF.

redis-cli INFO persistence
redis-check-aof --help
redis-check-rdb --help

RDB, AOF или вместе?

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

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

Практичная матрица выбора:

  • Кэш страниц, объектов, API-ответов: maxmemory, allkeys-lfu или allkeys-lru, RDB по желанию, AOF обычно не нужен.
  • Сессии: TTL для всех ключей, отдельный Redis при возможности, RDB или AOF everysec, осторожная eviction policy.
  • Очереди и важные временные состояния: noeviction, AOF everysec, мониторинг ошибок записи и свободного места.
  • Смешанная нагрузка: лучше разделить на несколько Redis-инстансов с разными портами, лимитами и политиками.

systemd limits: что проверить на VDS

Даже идеально подобранные настройки Redis могут упереться в systemd. Самые частые ограничения — количество открытых файлов, cgroup-лимит памяти и параметры unit-файла. Для Redis важен LimitNOFILE, потому что каждый клиент использует файловый дескриптор, а ещё есть сокеты, файлы persistence и внутренние нужды процесса.

Посмотрите текущие лимиты процесса:

pidof redis-server
cat /proc/$(pidof redis-server)/limits
systemctl show redis-server -p LimitNOFILE -p MemoryMax -p TasksMax
systemctl show redis -p LimitNOFILE -p MemoryMax -p TasksMax

На Debian/Ubuntu используйте имя redis-server, на RHEL-based и Fedora чаще redis. Если одна из команд вернула ошибку из-за отсутствующего сервиса — это нормально, используйте имя вашего unit.

Drop-in для Debian/Ubuntu:

sudo systemctl edit redis-server
[Service]
LimitNOFILE=65535
TasksMax=4096

Drop-in для RHEL-based и Fedora:

sudo systemctl edit redis
[Service]
LimitNOFILE=65535
TasksMax=4096

После изменения для Debian/Ubuntu:

sudo systemctl daemon-reload
sudo systemctl restart redis-server
cat /proc/$(pidof redis-server)/limits

После изменения для RHEL-based и Fedora:

sudo systemctl daemon-reload
sudo systemctl restart redis
cat /proc/$(pidof redis-server)/limits

С MemoryMax будьте осторожны. Если вы ставите cgroup-лимит памяти на Redis через systemd, он должен быть выше maxmemory с учётом RSS, fork, AOF/RDB rewrite, клиентов и фрагментации. Плохой вариант — maxmemory 2gb и MemoryMax=2200M на активной записи. В момент fork такой Redis может быть убит, хотя на уровне maxmemory всё выглядело корректно.

maxclients и файловые дескрипторы

Параметр maxclients ограничивает число клиентских подключений Redis. Если он выше доступного LimitNOFILE, Redis при старте уменьшит эффективное значение или начнёт жаловаться в журнале. Для веб-приложений проблема часто возникает не из-за реальных пользователей, а из-за пулов соединений: PHP-FPM воркеры, queue workers, cron-задачи и несколько приложений могут легко создать сотни подключений.

redis-cli CONFIG GET maxclients
redis-cli INFO clients
redis-cli CLIENT LIST

Если connected_clients растёт и не возвращается к норме, ищите утечки соединений в приложении. Если blocked_clients высок, проверьте команды, очереди и долгие операции. Увеличивать maxclients без понимания причины — временная мера, которая может просто перенести проблему на память и CPU.

Ядро Linux: overcommit и THP

Redis чувствителен к настройкам памяти ядра. Для фонового сохранения через fork обычно рекомендуют vm.overcommit_memory=1, иначе Redis может получить ошибку fork даже при наличии свободной памяти по факту. Transparent Huge Pages часто дают неприятные задержки, поэтому их обычно отключают для Redis-нагрузок.

Проверка:

cat /proc/sys/vm/overcommit_memory
cat /sys/kernel/mm/transparent_hugepage/enabled

Постоянная настройка overcommit_memory:

echo 'vm.overcommit_memory = 1' | sudo tee /etc/sysctl.d/99-redis.conf
sudo sysctl --system

Отключение THP лучше оформлять через systemd unit или tuned-профиль, в зависимости от дистрибутива и вашей политики администрирования. Не делайте это «одноразовой» командой в shell и не забывайте проверять после перезагрузки.

Диск и persistence: не только свободные гигабайты

Для RDB и AOF важен не только объём диска, но и задержки записи. На VDS с небольшим системным диском Redis может внезапно остановить записи, если stop-writes-on-bgsave-error yes и последний снимок завершился ошибкой. Это правильное безопасное поведение: лучше явно сломать запись, чем думать, что данные сохраняются, когда persistence уже не работает.

Проверьте каталог данных, свободное место и владельца файлов:

redis-cli CONFIG GET dir
redis-cli CONFIG GET dbfilename
redis-cli CONFIG GET appendonly
df -h
sudo du -sh /var/lib/redis
sudo ls -lah /var/lib/redis

Если AOF rewrite создаёт временный файл, места нужно больше, чем текущий размер AOF. Для крупных dataset держите запас. Если диск почти заполнен, Redis может продолжать обслуживать чтение, но записи и persistence окажутся под угрозой.

Мониторинг: какие метрики важны

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

  • used_memory и процент от maxmemory.
  • used_memory_rss и фрагментация.
  • evicted_keys: рост означает, что eviction реально происходит.
  • rejected_connections и connected_clients.
  • rdb_last_bgsave_status и aof_last_bgrewrite_status.
  • latest_fork_usec: резкий рост может объяснять latency spikes.
  • Свободное место и latency диска.

Для ручной проверки во время инцидента полезны такие команды:

redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO persistence
redis-cli INFO clients
redis-cli CONFIG GET maxmemory
redis-cli CONFIG GET maxmemory-policy

Безопасный порядок внедрения изменений

Не меняйте одновременно maxmemory, eviction policy, RDB, AOF и systemd limits на загруженном Redis без плана отката. Лучше двигаться шагами и после каждого шага смотреть метрики.

  1. Снимите текущую конфигурацию и показатели INFO.
  2. Сделайте резервную копию redis.conf и каталога данных, если persistence включён.
  3. Выставьте maxmemory с запасом, не равным всей RAM VDS.
  4. Выберите eviction policy под роль Redis, а не «самую популярную».
  5. Проверьте RDB/AOF и свободное место на диске.
  6. Настройте LimitNOFILE и проверьте фактические лимиты процесса.
  7. Перезапустите Redis в окно минимальной нагрузки или переключите приложение на резервный инстанс, если он есть.
  8. Наблюдайте за evicted_keys, latency, fork time и ошибками приложения.

Если Redis уже в аварийном состоянии и пишет OOM command not allowed, временно можно увеличить maxmemory или включить подходящую eviction policy через CONFIG SET. Но это только стабилизация. После неё нужно понять, почему dataset вырос: нет TTL, изменился профиль трафика, приложение начало писать большие значения, сломалась очистка или Redis используется не по назначению.

Пример конфигурации для Redis-кэша на небольшом VDS

Допустим, есть VDS с 2 ГБ RAM, Nginx, PHP-FPM и Redis для объектного кэша. Стартовая конфигурация может быть такой:

maxmemory 768mb
maxmemory-policy allkeys-lfu
save 900 1
save 300 10
save 60 10000
appendonly no

Это не «идеальный шаблон», а безопасная отправная точка. Если кэш активно прогревается и Redis не доходит до лимита, можно поднять maxmemory. Если eviction идёт постоянно, а hit ratio падает, возможно, памяти мало или приложение кэширует слишком крупные и редко используемые объекты.

Пример конфигурации для сессий и временного состояния

Для сессий на том же VDS я бы по возможности использовал отдельный Redis-инстанс или хотя бы отдельный сервер. Если это невозможно, задавайте TTL всем сессионным ключам и не смешивайте их с безлимитным кэшем.

maxmemory 512mb
maxmemory-policy noeviction
appendonly yes
appendfsync everysec
save 900 1
save 300 10

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

Типовые ошибки

  • Ставить maxmemory равным почти всей RAM VDS и забывать про fork.
  • Использовать allkeys-lru для Redis, где лежат очереди или важные состояния.
  • Включить AOF и не контролировать свободное место на диске.
  • Оставить маленький LimitNOFILE, а потом удивляться отказам подключений.
  • Полагаться на volatile eviction, когда большинство ключей без TTL.
  • Смешивать кэш, сессии и критичные данные в одном Redis-инстансе.
  • Не проверять восстановление из RDB/AOF до реальной аварии.

Короткий чек-лист для production

Перед тем как считать Redis на VDS готовым к нагрузке, пройдитесь по чек-листу. Он занимает несколько минут, но часто предотвращает неприятные инциденты.

  • maxmemory задан явно и оставляет запас RAM.
  • maxmemory-policy соответствует роли Redis.
  • Для кэш-ключей настроен TTL, особенно при volatile-политиках.
  • RDB/AOF включены или отключены осознанно, с понятным RPO.
  • Каталог dir находится на диске с достаточным свободным местом.
  • LimitNOFILE достаточен для maxclients и реального числа подключений.
  • MemoryMax, если используется, выше maxmemory с запасом.
  • Настроены алерты на eviction, persistence errors, клиентов, память и диск.
  • Есть проверенная процедура восстановления из RDB/AOF или резервной копии.

Redis хорош тем, что даёт большую производительность даже на небольшом VDS. Но он не прощает безлимитной памяти и неудачного смешивания ролей. Задайте maxmemory, выберите честную eviction policy, настройте RDB/AOF под допустимую потерю данных, проверьте systemd limits — и Redis станет предсказуемым компонентом инфраструктуры, а не источником ночных OOM-сюрпризов.

Поделиться статьей

Вам будет интересно

Docker Compose healthcheck и depends_on: чем заменить sleep при ожидании базы OpenAI Статья написана AI (GPT 5)

Docker Compose healthcheck и depends_on: чем заменить sleep при ожидании базы

Если контейнер приложения стартует раньше PostgreSQL, MySQL или Redis, не спешите добавлять sleep. Разберём, как правильно описать ...
AlmaLinux и Rocky Linux: настройка IP, DNS, gateway и static routes через nmcli на VDS OpenAI Статья написана AI (GPT 5)

AlmaLinux и Rocky Linux: настройка IP, DNS, gateway и static routes через nmcli на VDS

Покажу, как безопасно менять сетевые параметры на AlmaLinux и Rocky Linux с NetworkManager: найти профиль, задать статический IP, ...
AlmaLinux и Rocky Linux: настройка IPv4 и IPv6 через nmcli на VDS OpenAI Статья написана AI (GPT 5)

AlmaLinux и Rocky Linux: настройка IPv4 и IPv6 через nmcli на VDS

Разбираем, как на AlmaLinux и Rocky Linux управлять сетевыми профилями NetworkManager через nmcli: задать статический IPv4, добави ...