Ответ
TTL (Time To Live) — это механизм, который определяет время жизни записи в кеше. По истечении этого времени запись считается «протухшей» (stale) и подлежит удалению или обновлению при следующем запросе.
Зачем нужен TTL?
- Актуальность данных: Гарантирует, что пользователи не будут получать устаревшую информацию.
- Управление памятью: Автоматически очищает ненужные данные, предотвращая переполнение кеша и утечки памяти.
Реализация в Go
Существует два основных подхода к реализации TTL-кеша:
- Пассивная очистка (Lazy Eviction): Время жизни проверяется только в момент запроса данных (
Get
). Если запись просрочена, она удаляется и не возвращается пользователю. Это самый простой способ. - Активная очистка (Active Eviction): Фоновая горутина периодически сканирует весь кеш и удаляет просроченные записи. Этот подход лучше управляет памятью, но добавляет сложности.
Для большинства задач проще и надежнее использовать готовые библиотеки, например, github.com/patrickmn/go-cache
.
Пример простой реализации (пассивная очистка)
import (
"sync"
"time"
)
type CacheItem struct {
Value interface{}
Expiry int64 // Время истечения в Unix наносекундах
}
type TtlCache struct {
mu sync.RWMutex
items map[string]CacheItem
}
func (c *TtlCache) Set(key string, value interface{}, ttl time.Duration) {
c.mu.Lock()
defer c.mu.Unlock()
if c.items == nil {
c.items = make(map[string]CacheItem)
}
c.items[key] = CacheItem{
Value: value,
Expiry: time.Now().Add(ttl).UnixNano(),
}
}
func (c *TtlCache) Get(key string) (interface{}, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
item, found := c.items[key]
if !found {
return nil, false
}
// Проверяем, не истекло ли время жизни
if time.Now().UnixNano() > item.Expiry {
// Можно добавить удаление ключа здесь, но это потребует `c.mu.Lock()`
return nil, false
}
return item.Value, true
}