Два механизма, которые управляют жизнью данных в Redis: истечение по времени (TTL) и вытеснение при нехватке памяти (eviction). Непонимание первого даёт «вечный мусор», второго — необъяснимые пропажи ключей.
TTL: как ключи умирают
Redis не обходит все ключи по таймеру — это было бы O(N) каждую секунду. Истечение работает в два механизма:
- Пассивное: при обращении к ключу Redis проверяет его время истечения; истёкший ключ удаляется, клиент получает «не существует»;
- Активное: 10 раз в секунду Redis семплирует случайные ключи из словаря expires и удаляет истёкшие; если истёкло > 25% выборки — сразу повторяет цикл.
Итого: ключ без обращений тоже умрёт в разумное время, но точного момента гарантии нет — TTL в Redis это не «будильник», а вероятностный сборщик мусора.
SET session:abc "..." EX 3600 # секунды; PX — миллисекунды
TTL session:abc 3599
EXPIRE session:abc 60 # перезадать
EXPIRETIME session:abc # unix-время истечения
PERSIST session:abc # снять TTL
# Redis 7+: условные EXPIRE
EXPIRE key 60 NX # только если TTL ещё нет
EXPIRE key 60 XX # только если TTL уже есть
EXPIRE key 60 GT # только продлевая (новый TTL больше)
EXPIRE key 60 LT # только сокращая
Подводные камни TTL
- EXPIRE привязан к ключу, а не к значению:
HSETна ключ с TTL не продлевает TTL (и не снимает его) — запомните это; продление только явным EXPIRE; - SET снимает TTL: перезапись значения через SET/GETSET стирает время истечения
(проверьте:
SET k v EX 10,SET k v2,TTL k→ −1); - переименование сохраняет TTL (RENAME переносит expiry), но TTL сессии обычно продлевают именно на каждом обращении;
- часы сервера: TTL сравнивается с системным временем мастера; расхождение часов master/replica даёт разное «время смерти» одного ключа.
💡 Паттерн «скользящая сессия»: при каждом обращенииEXPIRE session:{id} 1800. А для «абсолютного» TTL дедлайна — сравнивайтеEXPIRETIMEв приложении.
Eviction: что удалять, когда память кончилась
maxmemory задаёт лимит данных (не всего процесса!). При его достижении включается
политика maxmemory-policy:
| Политика | Что делает | Для кого |
|---|---|---|
noeviction | ошибка OOM на запись | Redis как основное хранилище (по умолчанию) |
allkeys-lru | выкидывает редко используемый (по времени) ключ | классический кеш |
allkeys-lfu | выкидывает наименее частотный ключ | кеш с горячими ключами и сканами |
volatile-lru / volatile-lfu | LRU/LFU только среди ключей с TTL | смешанное БД+кеш |
volatile-ttl | выкидывает ключи с ближайшим истечением | редко |
allkeys-random / volatile-random | случайно | почти никогда |
LRU и LFU в Redis — приближённые
Настоящий LRU-список на миллиардах ключей дорог, поэтому Redis держит 24-битную метку
последнего доступа у каждого объекта и выбирает жертву из случайной выборки
(maxmemory-samples 5, по умолчанию). Точность растёт с выборкой, но идеального LRU
нет — и это нормально.
LFU (Redis 4+) хранит логарифмический счётчик частоты с затуханием по времени
(lfu-log-factor 10, lfu-decay-time 1): недавно горячий, но остывший
ключ «остывает» и может быть вытеснен. Для кешей это устойчивее LRU: редкий полный обход всех
данных (бэкап-скрипт, отчёт) не выметает горячие ключи.
💡 Дефолт для кеша — allkeys-lfu. Меняйте, только если
понимаете, почему. И никогда не полагайтесь на eviction для «важных» ключей: всё, что под
политикой вытеснения, может исчезнуть в любой момент.
Практика
- Продемонстрируйте, что SET снимает TTL, а HSET — нет.
CONFIG SET maxmemory 50mb,maxmemory-policy allkeys-lru; залейте 200 МБ benchmark'ом и посмотритеINFO stats | grep evicted. Повторите с lfu и сравните evicted_keys.- Сымитируйте «скан-кэш-трэшинг»: горячий ключ + фоновый обход 100 000 холодных — сравните выживание горячего ключа под LRU и LFU.
Мини-квиз
1. Ключ с TTL никто не читает. Когда он умрёт? — При очередном проходе активного истечения, когда попадёт в выборку; гарантированного момента нет.
2. Какая политика нужна «Redis = кеш + немного важных данных»? — volatile-*: вытесняются только ключи с TTL.
3. Почему LFU лучше переносит массовые обходы? — LRU метит «недавно тронутые» обходом ключи горячими; LFU смотрит на частоту и не даёт однократному скану вытеснить по-настоящему частые ключи.