Есть внешнее хранилище с двумя методами: получить и сохранить значение по
ключу. Нужно добавить поверх него кеширующий слой в памяти.
type Storage interface {
Get(ctx context.Context, key string) (string, error) // ErrNotFound, если ключа нет
Set(ctx context.Context, key, value string) error
}
var ErrNotFound = errors.New("not found")
func NewCache(s Storage) *Cache
func (c *Cache) Get(ctx context.Context, key string) (string, error)
func (c *Cache) Set(ctx context.Context, key, value string) error
Требования
- Write-through.
Set сначала пишет в хранилище и только при успехе
обновляет кеш.
- Если хранилище вернуло ошибку,
Set возвращает её (errors.Is находит
исходную), а ключ удаляется из кеша: в каком состоянии хранилище после
сбоя (например, таймаута), неизвестно.
- Read-through.
Get сначала смотрит в кеш. При попадании хранилище не
вызывается. При промахе значение читается из хранилища и кладётся в кеш.
- Ошибки хранилища, включая
ErrNotFound, возвращаются как есть и не
кешируются: следующий Get снова пойдёт в хранилище.
- Кеш используют из многих горутин, код проходит
go test -race.
- Запросы к хранилищу не выполняются под общей блокировкой: медленный ключ не
задерживает
Get и Set по другим ключам.
Пример
c := NewCache(redisStorage)
c.Set(ctx, "user:1", "Alice") // в хранилище, затем в кеш
c.Get(ctx, "user:1") // из кеша, хранилище не трогаем
c.Get(ctx, "user:2") // промах → хранилище → кеш
- Если много горутин одновременно промахнулись по одному ключу, в
хранилище уходит один запрос, а остальные ждут его результат (тот же
ответ или та же ошибка).
- Устаревшее значение не затирает свежее. Если
Get начал читать ключ из
хранилища, а в это время Set записал новое значение, кеш после этого
должен отдавать новое значение.
Устно: чем write-through отличается от write-back и cache-aside? Как
ограничить размер кеша и время жизни записей? Что будет с кешем в двух
репликах сервиса?
Разбор и эталонное решение — после своей попытки: на собеседовании подсказок не будет.
Сначала попробуй сам — подсказки не дают готовый ответ.