Привет, Хабр!
Сегодня мы коротко рассмотрим, как работает TTL в трёх популярных NoSQL‑хранилищах — Redis, MongoDB и Cassandra.
Что такое TTL и зачем он вообще нужен
TTL (Time To Live) — это не просто параметр в одну строчку, это фундаментальный способ сказать данным: «живи до… и исчезни без лишнего шума». По сути, это встроенная система самоудаления, срабатывающая без триггеров, без ручного вмешательства, без фоновых джобов. Задал срок — и система сама решает, когда пора отправить объект на покой.
Когда нужен TTL?
Кеш с известным сроком жизни
У тебя есть тяжёлый запрос в базу, но данные из него актуальны максимум 5 минут. Ты кладёшь результат в Redis или Memcached, ставишь TTL в 300 секунд — и больше не паришься. Данные сами удалятся, кеш сам обновится. Без TTL пришлось бы писать костыли: «а давай поставим updatedAt, проверим, сколько прошло, и если много — удалим вручную». TTL решает всё это встроенно.
Временные сессии, токены, капчи
Авторизация, верификация, восстановление паролей — все эти процессы строятся на одноразовых или временных данных. Сессионный токен должен жить, скажем, 30 минут. Капча — 90 секунд. TTL позволяет задать эту логику прямо в момент записи.
Soft delete без флагов
Иногда не хочется использовать is_deleted = true. Особенно когда данные реально должны исчезать. Например, временная корзина, истекающие права доступа, устаревшие подписки. TTL — это альтернатива флагам и ручной уборке: данные исчезают без участия разработчика. Флаги — штука хрупкая: забудешь фильтр, и вдруг старый мусор всплывает в API. TTL — это отсутствие самого объекта, и значит — никакой ошибки в выборке.
Рассмотрим конкретные реализации.
Redis
В Redis TTL задаётся на уровне ключей. И это чувствуется в API — всё заточено под скорость и прямоту.
Когда создаёшь ключ — TTL можно задать прямо при установке:
# Установить значение и задать TTL сразу SET session:123 "user_id_456" EX 60 SET verification:code_abc "9510" PX 300000 # 5 минут в миллисекундах
Если ключ уже существует, TTL можно установить отдельно:
# Установить TTL на существующий ключ EXPIRE session:123 120 # В секундах PEXPIRE session:123 1500 # В миллисекундах
Если нужно, чтобы ключ умер в конкретный момент времени — есть EXPIREAT:
# Установить время "смерти" как UNIX timestamp EXPIREAT session:123 1724010000 PEXPIREAT session:123 1724010123456 # Миллисекунды
TTL можно и снять:
# Сделать ключ бессмертным PERSIST session:123
И конечно, TTL можно проверить:
TTL session:123 # вернёт оставшееся время (секунды) PTTL session:123 # то же самое, но в миллисекундах
-1 означает, что TTL не установлен, -2 — ключа больше нет.
Lazy vs Active Expiration
Пример с lazy:
# ключ просрочен, но пока не удалён GET session:expired_key # Redis удалит его в этот момент
Active expiration — это то, что Redis делает в фоне, но если много ключей истекает одновременно, может возникнуть лаг.
Чтобы настроить Redis на агрессивную чистку:
# redis.conf hz 100 active-expire-effort 10
Но по опыту в проде TTL лучше делать немного разным, чтобы избежать массового одновременного удаления:
import random ttl = 60 + random.randint(0, 15) redis.set("token:user_123", access_token, ex=ttl)
MongoDB
В MongoDB TTL работает через индексы. Это не таймер на документ — это правило, встроенное в индекс. Пример установки:
// Документ будет жить 1 час после createdAt db.sessions.createIndex( { createdAt: 1 }, { expireAfterSeconds: 3600 } )
createdAt должен быть Date. Если это String или Number — TTL просто игнорируется. Документ живёт вечно.
Добавим документ:
db.sessions.insertOne({ _id: "abc123", userId: "u789", createdAt: new Date() })
Mongo начнёт отсчёт TTL от поля createdAt, а не от момента вставки. Чтобы обновить TTL — нужно обновить это поле:
// Обновим TTL вручную, обновив дату db.sessions.updateOne( { _id: "abc123" }, { $set: { createdAt: new Date() } } )
Пример ситуации, где TTL не обновится:
// TTL НЕ обновится, так как createdAt не трогали db.sessions.updateOne( { _id: "abc123" }, { $set: { status: "active" } } )
Удалить TTL‑индекс можно так:
db.sessions.dropIndex("createdAt_1")
После этого Mongo перестанет удалять старые записи — даже если поле createdAt продолжит обновляться.
Если нужна точность — лучше использовать другое поле, например expiresAt, и удалять вручную:
db.sessions.insertOne({ _id: "abc123", userId: "u789", expiresAt: new Date(Date.now() + 10 * 60 * 1000) }) // потом кроном или фоном: db.sessions.deleteMany({ expiresAt: { $lt: new Date() } })
Cassandra
Cassandra работает на низком уровне. TTL задаётся при вставке или обновлении, с ключевым словом USING TTL.
Пример при вставке:
-- строка живёт 1 час INSERT INTO sessions (id, user_id) VALUES ('abc123', 'user456') USING TTL 3600;
Пример при обновлении:
-- обновим только поле email, TTL применяется только к нему UPDATE sessions USING TTL 1800 SET email = 'a@x.com' WHERE id = 'abc123';
Если хочется, чтобы TTL продлился для всей строки — можно обновить все поля:
-- безопасное продление TTL всей строки UPDATE sessions USING TTL 7200 SET user_id = 'user456', email = 'a@x.com', last_seen = toTimestamp(now()) WHERE id = 'abc123';
Проверить TTL можно так:
-- покажет оставшийся TTL (в секундах) для поля SELECT TTL(user_id), TTL(email) FROM sessions WHERE id = 'abc123';
Если значение не имеет TTL — вернётся null.
Когда TTL истекает, Cassandra создаёт tombstone. Они удаляются позже во время compaction, но пока лежат и замедляют запросы.
Пример следствия:
-- Запрос, который начинает тормозить из-за миллиона tombstones SELECT * FROM user_logs WHERE user_id = 'u123';
Если ты не следишь за этим — таблица превращается в болото.
Следи за состоянием:
nodetool cfstats mykeyspace.sessions
И смотри на поля вроде Tombstone count, Live cells, Droppable tombstones.
Если хочется принудительно удалить всё, что протухло, можно запускать nodetool compact, но осторожно: это затратная операция.
Заключение
TTL — это не просто галочка «пусть сам удалится», а реальный инструмент управления данными. В Redis — быстро и точно, но можно перегреть систему. В Mongo — удобно, но не жди точности. В Cassandra — мощно, но шаг влево, шаг вправо — куча tombstone»ов и тормоза.
TTL надо понимать и чувствовать. Если ставишь — знай, когда, где и зачем. Пиши в комментах, как ты используешь TTL, где облажался или, наоборот, спас систему.
Если ваши проекты требуют работы с огромными объемами данных и сложной архитектурой, важно знать, как эффективно использовать инструменты и технологии для оптимизации процессов. На этих уроках вы получите практические знания, которые помогут вам решать актуальные задачи с помощью передовых решений.
-
10 июля, 20:00 — Архитектура и дизайн систем на основе NoSQL в облаках
Основы NoSQL в облаках, настройка баз и масштабирование в популярных платформах. -
24 июля, 20:00 — Практические кейсы использования ClickHouse
Обработка больших данных с помощью ClickHouse, примеры из веб-логов, IoT и финансов.
А чтобы проверить свой уровень знаний для обучения на курсе «NoSQL», пройдите бесплатное вступительное тестирование.
ссылка на оригинал статьи https://habr.com/ru/articles/923834/
Добавить комментарий