go-cache是单机内存缓存最省心的选择,线程安全、无依赖、支持ttl、api仅三个核心方法;bigcache/freecache/gcache面向高吞吐大数据量场景,需手动序列化、不支持直接存结构体、配置复杂、debug困难。

直接用 go-cache 就够了,它不是“之一”,而是单机内存缓存最省心的选择——线程安全、无依赖、带 TTL、API 就三个核心方法,连文档都不用翻两次。
为什么不是 bigcache / freecache / gcache?
它们都面向高吞吐、大数据量场景,但代价是:必须自己序列化 []byte、不能直接存结构体、初始化配置多、出错时 debug 路径长。如果你的缓存条目
-
bigcache绕过 GC 是靠把所有值扁平化进大块[]byte,但你要负责json.Marshal/Unmarshal,且Get返回的是拷贝,不是引用 -
freecache分段锁设计对超高并发有意义,但普通 Web 服务里 goroutine 竞争不到那个程度,反而要处理ErrCacheFull这类业务无关错误 -
gcache接口稍重,支持 LRU/LFU/ARC,但多数项目只用到“过期 + 最大容量”两个维度,其余策略纯属冗余
go-cache 的正确打开方式
它本质是带过期检查的 sync.Map + 定时清扫 goroutine,不黑魔法,所以行为可预测。
- 初始化只要一行:
cache := cache.New(5*time.Minute, 10*time.Minute)—— 第一个参数是默认 TTL,第二个是清理间隔(不是“每 10 分钟删一次”,而是“最多 10 分钟内删完过期项”) - 存值不用指定过期时间也能工作:
cache.Set("user:123", userObj, cache.DefaultExpiration),DefaultExpiration就是初始化时传的第一个参数 - 取值后别直接用指针:
if v, ok := cache.Get("key"); ok { u := v.(*User) }—— 类型断言失败会 panic,务必加ok判断,且注意v是 interface{},不是原始类型引用 - 不要在
Set里传闭包或含 channel/func 的 struct,go-cache不深拷贝,GC 时可能引发意外引用
什么时候该换别的库?
只有当压测出现明确瓶颈,且 profiling 指向缓存本身时才考虑迁移。
- pprof 显示
runtime.mallocgc占比 >30%,且缓存命中率 >95% → 可试bigcache(前提是能接受序列化成本) - 缓存条目长期 >100 万,且写入频繁导致
sync.Map锁竞争明显(看goroutine阻塞统计)→freecache分段更细,但得改存储逻辑 - 需要按访问频次淘汰(比如热榜数据),而非单纯时间淘汰 → 此时
gcache的LFU才真有用,别为了名字提前引入
真正容易被忽略的点是:缓存键的设计。用 "user:" + strconv.Itoa(id) 没问题,但别拼 SQL 或 JSON 字符串当 key —— 一旦格式微调,旧缓存就永远沉底。建议统一加版本前缀,比如 "v2:user:123",升级时清空旧前缀即可。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











