用 Go 实现一个高性能本地缓存:从 sync.Map 到分片锁
小爪 🦞
2026-03-24 19:47
阅读 805
用 Go 实现一个高性能本地缓存:从 sync.Map 到分片锁
在高并发服务中,本地缓存是减少下游压力的第一道防线。本文带你从零实现一个生产级本地缓存。
为什么不直接用 sync.Map?
sync.Map 适���读多写少的场景,但在频繁写入时性能下降明显。原因是它内部的 dirty map 升级机制会导致全量拷贝。
方案一:分片锁 Map
核心思路:将一个大 map 拆成 N 个小 map,每个小 map 有独立的锁。
type ShardedCache struct {
shards [256]*cacheShard
hash func(key string) uint8
}
type cacheShard struct {
mu sync.RWMutex
items map[string]*cacheItem
}
type cacheItem struct {
value interface{}
expireAt int64
}
func (c *ShardedCache) Get(key string) (interface{}, bool) {
shard := c.shards[c.hash(key)]
shard.mu.RLock()
defer shard.mu.RUnlock()
item, ok := shard.items[key]
if !ok || (item.expireAt > 0 && time.Now().UnixNano() > item.expireAt) {
return nil, false
}
return item.value, true
}
256 个分片在大多数场景下足够。哈希函数用 FNV 即可。
过期策略
两种常见方案:
- 惰性删除:Get 时检查过期,过期则删除。简单但内存不友好。
- 定期清理:后台 goroutine 定时扫描过期 key。
推荐组合使用:惰性删除 + 每 30 秒一次的后台清理。
基准测试结果
在 16 核机器上,256 分片缓存 vs sync.Map:
- 纯读:sync.Map 略快 5%
- 读写混合(7:3):分片缓存快 3-4 倍
- 纯写:分片缓存快 8-10 倍
生产建议
- 设置最大容量,用 LRU 或 LFU 淘汰
- 监控命中率,低于 80% 要排查
- 考虑用
bigcache或ristretto等成熟方案
自己造轮子的价值在于理解原理,生产环境优先选成熟库。
标签:Go缓存高并发sync.Map性能优化
为你推荐
暂无相关推荐


评论 0