【每日一库】一个零 GC 的缓存库:freecache

polaris · 2020-03-10 22:22:41 · 5279 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2020-03-10 22:22:41 的主题,其中的信息可能已经有所发展或是发生改变。

商业世界里,现金为王;架构世界里,缓存为王。

今天给大家推荐一个零 GC 开销、高并发性能的缓存库:FreeCache,项目地址:https://github.com/coocood/freecache,Star 数:2.5k+。

我们知道内存中的对象长期存在会带来昂贵的 GC 开销,使用 FreeCache,你可以在内存中缓存无限数量的对象,而不会增加延迟和吞吐量。

特性

  • 能存储数亿个条目
  • 零 GC 开销
  • 高并发线程安全访问
  • 纯 Go 实现
  • 过期支持
  • 类似 LRU 算法
  • 严格限制内存使用
  • 附带一个小服务器,支持带有管道功能的基本 Redis 命令
  • 迭代器支持

性能

这是基准测试结果与内置 map 的比较结果;Set 性能比内置 map 快约 2 倍;Get 性能比内置 map 慢约 1/2 倍。由于它是基于单线程做的基准测试,因此在多线程环境中,FreeCache 应该比单锁保护的内置 map 快许多倍。

BenchmarkCacheSet        3000000               446 ns/op
BenchmarkMapSet          2000000               861 ns/op
BenchmarkCacheGet        3000000               517 ns/op
BenchmarkMapGet         10000000               212 ns/op

使用示例

cacheSize := 100 * 1024 * 1024
cache := freecache.NewCache(cacheSize)
debug.SetGCPercent(20)
key := []byte("abc")
val := []byte("def")
expire := 60 // expire in 60 seconds
cache.Set(key, val, expire)
got, err := cache.Get(key)
if err != nil {
    fmt.Println(err)
} else {
    fmt.Println(string(got))
}
affected := cache.Del(key)
fmt.Println("deleted key ", affected)
fmt.Println("entry count ", cache.EntryCount())

它怎么做到零 GC 开销的?

FreeCache 通过减少指针数量避免了 GC 开销。无论其中存储了多少条目,都只有 512 个指针。通过 key 的哈希值将数据集分割为 256 个段。每个段只有两个指针,一个是存储键和值的环形缓冲区,另一个是用于查找条目的索引切片。每个段都有自己的锁,因此它支持高并发访问。


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

5279 次点击  ∙  2 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传