> Как реализовать шардирование кэша (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: Ozon
Стек: Go
> Пример ответа
Шардирование кэша в Go обычно реализуется через консистентное хеширование, чтобы минимизировать перераспределение данных при добавлении/удалении узлов. Основной подход - разбить ключи на логические шарды и распределить их по нескольким инстансам Redis или in-memory кэшам.
Пример реализации с использованием библиотеки hashicorp/memberlist для обнаружения узлов и кастомного консистентного хеширования:
GOimport ("github.com/hashicorp/memberlist""github.com/serialx/hashring")type ShardedCache struct {ring *hashring.HashRingnodes map[string]*CacheNode // map[nodeID] -> CacheNodeml *memberlist.Memberlist}type CacheNode struct {ID stringAddress stringCache *sync.Map // in-memory cache per node}func NewShardedCache() *ShardedCache {ring := hashring.New(nil)return &ShardedCache{ring: ring,nodes: make(map[string]*CacheNode),}}func (sc *ShardedCache) Get(key string) (interface{}, bool) {nodeID, _ := sc.ring.GetNode(key)node, ok := sc.nodes[nodeID]if !ok {return nil, false}return node.Cache.Load(key)}func (sc *ShardedCache) Set(key string, value interface{}) {nodeID, _ := sc.ring.GetNode(key)node, ok := sc.nodes[nodeID]if !ok {// fallback: можно записать на ближайший доступный узелreturn}node.Cache.Store(key, value)}// При изменении топологии (добавление/удаление узла) пересоздаём ringfunc (sc *ShardedCache) UpdateNodes(newNodes []string) {sc.ring = hashring.New(newNodes)// Очистка/миграция данных по необходимости}
Ключевые моменты:
- Используйте консистентное хеширование (например,
serialx/hashring) для равномерного распределения. - Для обнаружения узлов в кластере подойдёт
memberlist(Gossip protocol) или etcd. - Каждый узел хранит свою часть данных в
sync.Mapили Redis. - При изменении числа шардов пересчитывайте только часть ключей (благодаря консистентному хешированию).
- Для production добавьте репликацию (каждый ключ на N узлах) и механизм перебалансировки при сбоях.
> Похожие задачи по Go
Почему использовать UUID вместо int для идентификаторов
Как работает двусвязный список в LRU кэше
Какие ключевые особенности типа slice в Go
Какие стратегии масштабирования кэша существуют
> Похожие задачи по backend
Почему использовать UUID вместо int для идентификаторов
Как работает двусвязный список в LRU кэше
Какие ключевые особенности типа slice в Go
Какие стратегии масштабирования кэша существуют
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью