Какие существуют способы реализации и стратегии обновления/инвалидации кэша в Go?

Ответ

Реализация кэша в Go зависит от требований к производительности, согласованности данных и сложности.

1. Простая реализация (in-memory)

Для базового кэша можно использовать map с sync.RWMutex для обеспечения потокобезопасности.

type Cache struct {
    sync.RWMutex
    items map[string]interface{}
}

func (c *Cache) Set(key string, value interface{}) {
    c.Lock()
    defer c.Unlock()
    c.items[key] = value
}

func (c *Cache) Get(key string) (interface{}, bool) {
    c.RLock()
    defer c.RUnlock()
    item, found := c.items[key]
    return item, found
}

2. Кэш с TTL (Time-To-Live)

Для автоматического удаления устаревших записей кэш дополняется временем жизни.

type CacheItem struct {
    Value      interface{}
    Expiration int64
}

// При добавлении элемента
expiration := time.Now().Add(5 * time.Minute).UnixNano()
c.items[key] = CacheItem{Value: value, Expiration: expiration}

// При получении нужна проверка
if item.Expiration < time.Now().UnixNano() {
    // Элемент устарел
    return nil, false
}

3. Стратегии инвалидации кэша

Выбор стратегии — ключевой аспект работы с кэшем:

  • Cache-Aside (Чтение/запись с кешированием): Самый распространенный паттерн. Приложение при чтении сначала проверяет кэш. Если данных нет (cache miss), оно читает их из БД, сохраняет в кэш и возвращает. При записи приложение обновляет БД, а затем инвалидирует (удаляет) соответствующую запись в кэше.
  • Write-Through (Сквозная запись): Приложение пишет данные одновременно и в кэш, и в БД. Гарантирует консистентность, но увеличивает задержку записи.
  • Write-Back (Отложенная запись): Приложение пишет данные только в кэш, который, в свою очередь, асинхронно записывает их в БД через некоторое время. Очень быстрые операции записи, но есть риск потери данных при сбое кэша до того, как данные попали в БД.

4. Готовые решения

Для сложных сценариев (LRU/LFU-вытеснение, шардирование) лучше использовать проверенные библиотеки:

  • github.com/patrickmn/go-cache: Простой in-memory кэш с TTL.
  • github.com/dgraph-io/ristretto: Высокопроизводительный, конкурентный кэш.
  • github.com/allegro/bigcache: Эффективный in-memory кэш для больших объемов данных.