概述
这是官方
Github
主页上的项目介绍,和 fasthttp
名字一样以 fast
打头,作者对项目代码的自信程度可见一斑。此外该库的核心代码非常轻量, 笔者本着学习的目的分析下内部的代码实现。基准测试
官方给出了
fastcache
, bigcache
, 标准库 map
, sync.Map
的基准测试比较结果。从测试的结果中可以看到:
fastcache
在所有操作上都要比bigcache
快
fastcache
在只写 + 读写混合
操作比标准库的map, sync.Map
要快,只读
操作比后者要慢
组件特性
- 高性能
- 线程安全
- 设计为存储大量数据 (没有 GC 开销)
- 自动删除比较旧数据
- 使用简单
- 源代码简单且非常轻量
- 缓存数据可以保存到文件,也可以从文件中加载
示例
从示例代码可以看到,除了初始化时需要指定缓存的大小,组件提供的 API 就是常规的 “键值对” 语义操作,例如
Get
, Set
, Del
等。源码分析
笔者选择的 fastcache 版本为
v1.12.1
。哈希算法
fastcache
库内部采用的哈希算法为 XXH64。数据结构
常量
因为
桶的大小
和 桶的数据存储重写次数
两个字段存储在一个变量中 (可以并发原子操作),所以这里使用两个常量来区分这两个字段各自的字节数。Cache 对象
Cache
用来表示 缓存对象
,包含了 2 个字段:- 用于存储数据的 bucket 桶,数据结构是数组,固定长度 512
- 用于表示
GetBig/SetBig
(针对大数据读写) 方法调用的统计信息
bucket 桶
bucket
桶负责具体数据的获取和存储,每个桶的数据存放量是根据 缓存的数据总量
平均计算得出的 (例如总量为 2GB
, 那么每个桶的数据就是 4MB
)。数据结构图

方法
创建缓存对象
New
根据容量参数创建一个缓存对象并返回。桶初始化
桶重置
Set 操作
Set
操作分成两部分完成,首先计算出指定 key
所在的桶,然后将 value
存入对应的桶中。Get 操作
Get
操作分成两部分完成,首先计算出指定 key
所在的桶,然后从桶中获取对应的 value
, 作为可选性,调用方可以将接收 value
的变量作为第一个参数传入 (复用 []byte, 节省内存)。桶的哈希缓存重建
调用关系图

高性能设计细节
fastcache
采用类似 bigcache
的设计思路:缓存
由许多桶
组成,每个桶都持有一个锁 (分段锁),这样可以提高多核 CPU 的性能,因为多个 CPU 可以同时访问不同的桶
- 每个桶由一个哈希索引 (数据块的位置) 和 65536 个数据块组成,每个桶的指针数量最多为
桶的存储容量 / 64KB
(这里指 bucket.chunks 字段)。 例如,64GB 缓存将包含大约 1M 指针,而类似大小的 map[string][]byte 将包含大约 1B 指针,这将导致巨大的 GC 开销
从设计上来说,和每个桶持有一个大的数据块相比,
fastcache
采用的 64KB 的数据块减少了内存碎片和总内存使用量。 此外当从 全局数据块空闲区
获取数据块时,会直接调用 Mmap
分配到堆外内存,减少了总内存使用量,因为 GC 会更频繁地收集未使用的内存,无需调整 GOGC。使用约束和限制
fastcache
组件库的使用有 4 个约束条件,在技术选型的时候比较重要,不过从下面的 4 点要求来看,实际应用中可以通过设计合理的数据类型来规避这些约束条件。- 缓存数据的
key
和value
数据类型必须是[]byte
, 如果是其他类型,必须在存储前转换为[]byte
- 缓存数据大小超过
64K
, 必须调用SetBig
方法存储
- 缓存数据没有过期时间,只有当缓存数据的数量溢出时,才会删除比较旧的数据,通用的实践是将过期时间存入数据中
- 缓存数据采用
环形缓冲区
存储,这意味着数据量过大的情况下,新的数据会重写并覆盖掉旧的数据
此外值得注意的是,Set 方法并没有返回值来表示操作的执行结果,这种设计丢失了方法语义,并且在某些极端情况下造成难以排查的 Bug。
小结
本文主要分析了
fastcache
组件的缓存设计与实现,我们可以从中学习到 3 个非常重要的设计技巧: 采用分段锁降低锁的粒度
, 采用指纹 + 哈希索引快速定位数据位置
, map 使用 [uint64]uint32 作为非指针优化从而避免 GC
, 在组件的基础上,也许我们可以进一步优化 (例如将桶的锁粒度细化到数据块)?感兴趣的读者可以通过修改源代码进行测试 (毕竟 fastcache 的源代码非常轻量)。 此外需要注意的是,fastcache
提供的 Get
, Set
方法参数类型都是 []byte
, 这意味着在调用方法前,必须现将具体的数据类型或对象转换为 []byte
, 这会带来额外的 CPU 消耗。 最后,fastcache
提供的 缓存数据 <=> 文件
写入和加载功能以及 全局数据块空闲区
,由于时间关系,本文不再分析其具体代码实现。Reference
扩展阅读

转载申请
本作品采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,商业转载请联系作者获得授权。