文章目录
- [fastcache:为 Go 设计的低 GC 压力内存缓存](#fastcache:为 Go 设计的低 GC 压力内存缓存)
fastcache:为 Go 设计的低 GC 压力内存缓存
fastcache 在 GitHub 上已经拿到 2,367 Star。
它是 VictoriaMetrics 团队开源的 Go 内存缓存库,目标是在高并发场景下缓存大量条目,同时避开 Go GC 带来的性能抖动。

1、它解决了什么问题
Go 的标准 map 和 sync.Map 在条目数量变大时会遇到同一个问题:GC 压力。每个键值对都是一个独立指针对象,条目一多,堆上的指针数量暴涨,GC 停顿时间跟着变长。
fastcache 的做法是减少堆上的指针数量。它把数据切分成 64KB 的 chunk,每个 bucket 内部只维护 O(chunkCount) 级别的指针。官方数据提到,64GB 缓存大约只产生 100 万个指针,而同样规模的 mapstring\[\]byte 会产生约 10 亿个指针。差距主要来自 chunk 化存储。
这个数量级的差异直接决定了 GC 的扫描成本。指针越少,GC 遍历堆图的速度越快,服务延迟的尖峰也就越少。

2、主要特性
fastcache 的特性可以概括为以下几点:
- 线程安全:多个 goroutine 可以并发读写同一个缓存实例。
- 写入快:在多核 CPU 上性能可扩展,写入场景下比 BigCache、标准 map 和 sync.Map 更快。
- 内存省:通过 chunk 化存储减少堆指针数量,降低 GC 压力。
从 README 提供的 benchmark 数据来看,fastcache 在 Set、Get 以及 SetGet 混合场景中都保持了较低的内存分配。Set 操作每次仅分配约 1142 字节,而 BigCache 和 sync.Map 的分配量高出几个数量级。
- 自动淘汰:达到创建时指定的最大容量后,旧条目会被清理。
- 简单 API:接口为零分配模式设计,调用开销低。
- 持久化:支持 SaveToFile 和 LoadFromFile,方便缓存状态落盘与恢复。
- AppEngine 兼容:可在 Google AppEngine 环境中运行。
3、架构要点
fastcache 借鉴了 BigCache 的分桶思路,并做了细节优化。
缓存由多个 bucket 组成,每个 bucket 有自己的锁。多核 CPU 可以同时访问不同 bucket,降低锁竞争。每个 bucket 内部包含一个 hash(key) 到 (key, value) 位置的映射,以及若干 64KB 的 byte slice chunk。条目编码后写入 chunk,而不是为每个条目单独分配内存。
分桶机制带来的另一个好处是写操作可以并行。多个 goroutine 同时写入时,只要命中不同 bucket,就不会互相阻塞。测试数据显示,在 GOMAXPROCS=4 的环境下,fastcache 的 Set 操作比 BigCache 和标准 map 都要快。
64KB 这个尺寸经过权衡:既能降低内存碎片,又能让 GC 更频繁地回收未使用内存,减少 GOGC 调参的必要性。如果环境允许,chunk 会尝试分配在堆外,进一步降低 GC 压力。
4、使用限制
使用 fastcache 之前需要了解几个约束:
- 键和值都必须是 byte slice,其他类型需要先序列化。
- 超过 64KB 的大条目需要使用 SetBig 接口。
- 没有内置过期时间,条目只在缓存容量满时被淘汰。如果需要 TTL,可以在 value 里编码过期时间,读取后自行校验。
这些限制是 VictoriaMetrics 团队为了性能做出的取舍。在他们的使用场景里,缓存条目本身不会过期,只需要在容量满时淘汰即可。
5、适合谁用
如果你在写 Go 服务,需要缓存大量对象,同时对 GC 延迟敏感,fastcache 值得一看。它适合以下场景:
- 指标存储、时序数据库等需要大缓存的系统。
- 高并发读写混合的在线服务。
- 希望减少 GC 调优、获得稳定延迟的后端应用。
由于源码没有引入复杂依赖,接入成本很低。你可以直接通过 go get 引入,也可以在初始化时指定 maxBytes 控制容量上限。
源码体积不大,API 也简单,读完核心代码后可以根据业务需求二次封装。
以在初始化时指定 maxBytes 控制容量上限。
源码体积不大,API 也简单,读完核心代码后可以根据业务需求二次封装。