Redis: память и политики вытеснения ключей
Что решаем
Redis часто начинают использовать как кэш и забывают поставить лимит памяти. Потом в тот же Redis добавляют сессии или очереди, и настройка allkeys-lru, нормальная для кэша, внезапно становится опасной.
Ключевой момент: maxmemory-policy действует на весь Redis-инстанс. Номера баз REDIS_DB=0 и REDIS_CACHE_DB=1 помогают разделить ключи логически, но не дают отдельной политики вытеснения для каждой базы.
Лимит памяти
Минимальная настройка в конфиге Redis:
maxmemory 512mb
maxmemory-policy allkeys-lru
После правки:
sudo systemctl restart redis-server
На другой системе служба может называться redis:
sudo systemctl restart redis
Проверить, что Redis реально поднял новые значения:
redis-cli CONFIG GET maxmemory
redis-cli CONFIG GET maxmemory-policy
redis-cli INFO memory
Про запас RAM
При включённых persistence или replication не выделяйте Redis всю свободную память. Ему нужен запас на служебные буферы и фоновые операции.
Какая политика для чего
| Политика | Когда использовать |
|---|---|
allkeys-lru | Хороший старт для отдельного Redis под кэш: вытесняются давно неиспользуемые ключи. |
allkeys-lfu | Подходит, если важнее сохранить часто читаемые ключи, а не просто недавно использованные. |
volatile-ttl | Работает только с ключами, у которых есть TTL. Полезно, если приложение осознанно задаёт сроки жизни. |
volatile-lru | Вытесняет только ключи с TTL. Если таких ключей нет, Redis фактически упрётся в память. |
noeviction | Redis не удаляет ключи сам, а начинает возвращать ошибку на записи, когда память закончилась. |
Для Laravel-кэша я обычно выбираю allkeys-lru или allkeys-lfu. Для Redis, где вместе лежат кэш, сессии и очереди, это уже риск: Redis может вытеснить не тот ключ.
Laravel: кэш, сессии и очереди
Если Redis используется только как кэш, потеря ключа нормальна: Laravel пересчитает значение. Поэтому отдельный Redis-инстанс под кэш с allkeys-lru — простой и понятный вариант.
С сессиями и очередями другой разговор. Вытесненная сессия — это внезапный logout. Вытесненный ключ очереди — потерянная или сломанная обработка job. Поэтому для смешанного Redis я выбираю один из двух путей:
- разнести кэш и очереди/сессии по разным Redis-инстансам;
- оставить
noevictionи следить за памятью, чтобы Redis не молча удалял важные ключи.
Разные номера баз внутри одного Redis удобны для порядка, но не заменяют отдельный инстанс, когда нужна разная политика памяти.
Диагностика
Эти команды показывают, упирается ли Redis в лимит и насколько полезен кэш:
redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO keyspace
В INFO stats смотрю на evicted_keys, expired_keys, keyspace_hits и keyspace_misses. Если evicted_keys быстро растёт, памяти мало или политика выбрана плохо. Если много keyspace_misses, кэш может быть слишком маленьким или TTL слишком коротким.
Для грубой оценки hit rate:
keyspace_hits / (keyspace_hits + keyspace_misses) * 100
Два рабочих профиля
Redis только под Laravel-кэш
maxmemory 512mb
maxmemory-policy allkeys-lru
Это спокойный вариант для кэша: при нехватке памяти Redis выбросит старые ключи, приложение пересчитает данные.
Redis для кэша, сессий и очередей вместе
maxmemory 1gb
maxmemory-policy noeviction
Здесь лучше получить явную ошибку записи и алерт, чем молча потерять сессию или job. Но правильнее — вынести кэш в отдельный Redis, если проект начал расти.
Временная смена политики
Для быстрой проверки можно поменять настройки на лету:
redis-cli CONFIG SET maxmemory 512mb
redis-cli CONFIG SET maxmemory-policy allkeys-lru
Но это не замена конфигу: после перезапуска значения могут откатиться. Постоянные настройки должны лежать в redis.conf или в конфигурации контейнера.