bigcache
BigCache是如何做到高性能的?
加速并发访问
在BigCache中,缓存使用了分段(shard)存储,每一个shard有一个lock,减小了lock的粒度。
避免GC开销
map非指针优化是指: 如果在map的键和值中使用没有指针, 那么GC将忽略它。BigCache使用map[uint64]uint32,其中键是散列的,值是entries(某条数据)的偏移量。
entries被全部保存在[]byte中,因此海量的缓存数据只给GC增加了1个对象,进一步降低了GC的负担。 由于[]byte除了自身对象并不包含其他指针数据,所以GC对所有的BigCache对象的标记时间是O(1)的。
BigCache的原理
type BigCache struct {
shards []*cacheShard // 缓存分片数据
lifeWindow uint64
clock clock
hash Hasher
config Config
shardMask uint64
close chan struct{}
}
type cacheShard struct {
hashmap map[uint64]uint32 // 索引,对应KEY在entries中的位置和长度
entries queue.BytesQueue // 实际数据存储
lock sync.RWMutex
entryBuffer []byte
onRemove onRemoveCallback
isVerbose bool
statsEnabled bool
logger Logger
clock clock
lifeWindow uint64
hashmapStats map[uint64]uint32
stats Stats
}
type BytesQueue struct {
full bool
array []byte // 实际数据存储
capacity int
maxCapacity int
head int
tail int // 下次可以插入的位置
count int
rightMargin int
headerBuffer []byte
verbose bool
}设计思想: 根据key可以计算出hash,即可锁定key所属的shard分片, shard分片的hashmap字段用于存储key对应在entries的index(位置和长度), 写入数据时结合value需要的[]byte长度和value在entries中新增插入的位置,这2个信息共同组成index信息写入hashmap(键是key的hash,值是在entries的index), 那么在查询时就可以拿key的hash在hashmap中查找存储在entries中的位置和长度了,取出即可。
过期策略
BigCache只能在全局的Config中做配置,每一个key的过期时间窗口都是相同的,过期删除策略维护的是最近的时间窗口,Set同一个key会刷新它的过期时间。
一个例子
LifeWindow & CleanWindow
一条数据在Set之后,经历LifeWindow时间之后会被标记为可清除状态(在它被删除之前仍然可以Get到它)。
全局的清理协程每CleanWindow执行一次清理,删除被标记为可清除状态的数据。
Last updated
Was this helpful?