Обобщённый потокобезопасный кеш
Вопрос
Спроектируйте вслух обобщённый потокобезопасный кеш Cache[K, V] с TTL. Какие ограничения на типы, какие методы, как устроите вытеснение?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Сигнатура `Cache[K comparable, V any]`, comparable нужен для ключа мапы
Хранение `map[K]entry[V]` с временем истечения, sync.RWMutex или шардирование
Get возвращает `(V, bool)` и нулевое значение при промахе
Удаление просроченных: лениво при чтении плюс фоновая горутина с ticker и способом её остановить
Ограничение размера: LRU через container/list или кольцо
Защита от лавины: singleflight при загрузке
Что могут спросить следом
- Как избежать утечки фоновой горутины?
- Как тестировать TTL без реального ожидания?
Разбор
Тип Cache[K comparable, V any]: ключ должен быть comparable, потому что это ключ мапы. Внутри map[K]entry[V], где entry хранит значение и expiresAt. Защита: sync.RWMutex, а при высокой конкуренции шардирование на N мап по хешу ключа. Get(k) (V, bool): при промахе или истёкшей записи возвращаю var zero V и false, просроченное удаляю лениво. Фоновая очистка: горутина с time.Ticker, которая останавливается методом Close или по context, иначе горутина утечёт вместе с кешем. Для ограничения размера добавляю LRU: двусвязный список container/list и мапа на элементы списка, при вставке сверх лимита удаляю хвост. Для загрузки при промахе GetOrLoad с singleflight, чтобы сто одновременных промахов не пошли в базу сто раз. Время подменяю функцией now func() time.Time в тестах, а в Go 1.25 для этого есть ещё testing/synctest с фиктивными часами.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.