> Как организовать мьютексы для многопоточной работы с данными по разным пользователям без блокировки всего стореджа (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Русклимат

Стек: Go

> Пример ответа

Для эффективной работы с данными разных пользователей без блокировки всего хранилища в Go применяется шардирование мьютексов (sharded mutexes) - разделение общего пула блокировок на независимые сегменты на основе идентификатора пользователя.

Пример реализации:

GO
type UserCache struct {
shards []sync.RWMutex
data map[int]string
shardMask uint64 // для быстрого вычисления индекса
}
func NewUserCache(shardCount int) *UserCache {
// shardCount должен быть степенью двойки для маски
return &UserCache{
shards: make([]sync.RWMutex, shardCount),
data: make(map[int]string),
shardMask: uint64(shardCount - 1),
}
}
func (c *UserCache) getShard(userID int) *sync.RWMutex {
return &c.shards[uint64(userID)&c.shardMask]
}
func (c *UserCache) Get(userID int) (string, bool) {
shard := c.getShard(userID)
shard.RLock()
defer shard.RUnlock()
val, ok := c.data[userID]
return val, ok
}
func (c *UserCache) Set(userID int, value string) {
shard := c.getShard(userID)
shard.Lock()
defer shard.Unlock()
c.data[userID] = value
}

Ключевые моменты:

  • Каждый пользователь блокирует только свой шард, остальные шарды доступны параллельно
  • sync.RWMutex позволяет конкурентное чтение для одного пользователя
  • Количество шардов выбирается под нагрузку (обычно 16-256)
  • Для более сложных сценариев используйте sync.Map или библиотеки типа concurrent-map

Этот подход масштабируется горизонтально и предотвращает "глобальный стоп" при работе с разными пользователями.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью