Как стать автором
Поиск
Написать публикацию
Обновить
524.83
OTUS
Развиваем технологии, обучая их создателей

Коротко про TTL в NoSQL-хранилищах: Redis, MongoDB и Cassandra

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров2.4K

Привет, Хабр!

Сегодня мы коротко рассмотрим, как работает 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, где облажался или, наоборот, спас систему.


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

А чтобы проверить свой уровень знаний для обучения на курсе "NoSQL", пройдите бесплатное вступительное тестирование.

Теги:
Хабы:
+5
Комментарии2

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS