golang高效处理GB级数据的键值缓存插件库BigCache的使用
Golang高效处理GB级数据的键值缓存插件库BigCache的使用
简介
BigCache是一个快速、并发、支持淘汰机制的内存缓存库,专门设计用于存储大量条目而不影响性能。BigCache将条目保存在堆上但避免了GC对它们的影响。为了实现这一点,它使用字节切片进行操作,因此在大多数用例中需要在缓存前后进行条目的(反)序列化。
要求Go 1.12或更高版本。
基本使用
简单初始化
import (
"fmt"
"context"
"github.com/allegro/bigcache/v3"
"time"
)
// 创建一个生命周期为10分钟的缓存
cache, _ := bigcache.New(context.Background(), bigcache.DefaultConfig(10 * time.Minute))
// 设置键值
cache.Set("my-unique-key", []byte("value"))
// 获取值
entry, _ := cache.Get("my-unique-key")
fmt.Println(string(entry)) // 输出: value
自定义初始化
当可以提前预测缓存负载时,最好使用自定义初始化,这样可以避免额外的内存分配。
import (
"log"
"time"
"github.com/allegro/bigcache/v3"
)
config := bigcache.Config {
// 分片数量(必须是2的幂)
Shards: 1024,
// 条目可以被淘汰的时间
LifeWindow: 10 * time.Minute,
// 清理过期条目的时间间隔
// 如果设置为<=0则不执行任何操作
// 设置为<1秒会适得其反,因为bigcache有1秒的分辨率
CleanWindow: 5 * time.Minute,
// rps * lifeWindow, 仅用于初始内存分配
MaxEntriesInWindow: 1000 * 10 * 60,
// 最大条目大小(字节),仅用于初始内存分配
MaxEntrySize: 500,
// 打印关于额外内存分配的信息
Verbose: true,
// 缓存不会分配超过此限制的内存,单位为MB
// 如果达到此值,则可以为新条目覆盖最旧的条目
// 0表示没有大小限制
HardMaxCacheSize: 8192,
// 当最旧的条目由于过期时间或没有空间而被移除时触发的回调
// 将返回一个表示原因的位掩码
// 默认值为nil,表示没有回调
OnRemove: nil,
// OnRemoveWithReason是一个回调,当最旧的条目由于过期时间或没有空间而被移除时触发
// 将传递一个表示原因的常量
// 默认值为nil,表示没有回调
// 如果指定了OnRemove,则忽略此选项
OnRemoveWithReason: nil,
}
cache, initErr := bigcache.New(context.Background(), config)
if initErr != nil {
log.Fatal(initErr)
}
cache.Set("my-unique-key", []byte("value"))
if entry, err := cache.Get("my-unique-key"); err == nil {
fmt.Println(string(entry))
}
LifeWindow 和 CleanWindow
LifeWindow
是一个时间。超过这个时间后,条目可以被视为死亡但不会被删除。CleanWindow
是一个时间。超过这个时间后,所有死亡的条目将被删除,但仍有生命的条目不会被删除。
性能比较
BigCache与freecache和原生map进行了比较。基准测试使用i7-6700K CPU @ 4.00GHz和32GB RAM在Ubuntu 18.04 LTS(5.2.12-050212-generic)上进行。
写入和读取性能
BenchmarkMapSet-8 12999889 376 ns/op
BenchmarkConcurrentMapSet-8 4355726 1275 ns/op
BenchmarkFreeCacheSet-8 11068976 703 ns/op
BenchmarkBigCacheSet-8 10183717 478 ns/op
BenchmarkMapGet-8 16536015 324 ns/op
BenchmarkConcurrentMapGet-8 13165708 401 ns/op
BenchmarkFreeCacheGet-8 10137682 690 ns/op
BenchmarkBigCacheGet-8 11423854 450 ns/op
BigCache的写入和读取速度比freecache快。写入map是最慢的。
GC暂停时间
Number of entries: 20000000
GC pause for bigcache: 1.506077ms
GC pause for freecache: 5.594416ms
GC pause for map: 9.347015ms
测试显示了填充2000万条目时GC暂停的时间长度。Bigcache和freecache有非常相似的GC暂停时间。
工作原理
BigCache依赖于Go 1.5版本中提出的优化。这种优化指出,如果在键和值中没有指针的map被使用,那么GC将忽略其内容。因此BigCache使用map[uint64]uint32
,其中键是哈希值,值是条目的偏移量。
条目保存在字节切片中,再次避免GC。字节切片的大小可以增长到GB级别而不影响性能,因为GC只会看到它的单个指针。
碰撞处理
BigCache不处理碰撞。当插入新项目并且其哈希与先前存储的项目碰撞时,新项目将覆盖先前存储的值。
BigCache vs FreeCache
两种缓存都提供相同的核心功能,但它们以不同的方式减少GC开销。BigCache依赖于map[uint64]uint32
,freecache实现了自己的基于切片的映射以减少指针数量。
BigCache相对于freecache的一个优势是您不需要提前知道缓存的大小,因为当bigcache已满时,它可以为新条目分配额外的内存,而不是像freecache当前所做的那样覆盖现有条目。但是也可以在bigcache中设置硬最大大小。
HTTP服务器
此包还包括一个易于部署的BigCache HTTP实现,可以在server包中找到。
许可证
BigCache在Apache 2.0许可证下发布。
更多关于golang高效处理GB级数据的键值缓存插件库BigCache的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang高效处理GB级数据的键值缓存插件库BigCache的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang高效处理GB级数据的键值缓存:BigCache使用指南
BigCache是一个专为Golang设计的高性能键值缓存库,特别适合处理GB级别的缓存数据。它通过优化内存分配和减少GC压力,实现了极高的吞吐量。
BigCache核心特性
- 零GC压力:使用
map[uint64]uint32
和自定义内存分配机制避免GC扫描 - 高并发:分片设计减少锁竞争
- 高效内存利用:预分配内存减少碎片
- 简单API:类似标准map的操作接口
安装BigCache
go get github.com/allegro/bigcache/v3
基本使用示例
package main
import (
"fmt"
"time"
"github.com/allegro/bigcache/v3"
)
func main() {
// 创建缓存实例
cache, err := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute))
if err != nil {
panic(err)
}
// 设置缓存
err = cache.Set("key1", []byte("value1"))
if err != nil {
fmt.Println("Set error:", err)
}
// 获取缓存
entry, err := cache.Get("key1")
if err != nil {
fmt.Println("Get error:", err)
} else {
fmt.Printf("Got value: %s\n", entry)
}
// 删除缓存
err = cache.Delete("key1")
if err != nil {
fmt.Println("Delete error:", err)
}
}
高级配置选项
config := bigcache.Config{
// 缓存存活时间
LifeWindow: 10 * time.Minute,
// 清理过期缓存的间隔
CleanWindow: 5 * time.Minute,
// 分片数量(必须是2的幂)
Shards: 1024,
// 最大缓存条目数(仅在初始分配内存时使用)
MaxEntriesInWindow: 1000 * 10 * 60,
// 最大条目大小(字节)
MaxEntrySize: 500,
// 是否统计缓存命中率
StatsEnabled: true,
// 当缓存满时的回调函数
OnRemove: func(key string, entry []byte) {
fmt.Printf("Evicted: %s\n", key)
},
// 是否在删除时复制值(安全但性能较低)
HardMaxCacheSize: 8192, // MB
}
cache, err := bigcache.NewBigCache(config)
性能优化技巧
- 合理设置分片数:默认1024分片适合大多数场景,高并发场景可增加
- 预分配内存:根据数据量设置
MaxEntriesInWindow
减少扩容开销 - 批量操作:减少锁竞争
// 批量写入示例
func batchSet(cache *bigcache.BigCache, data map[string][]byte) error {
for k, v := range data {
if err := cache.Set(k, v); err != nil {
return err
}
}
return nil
}
监控与统计
// 启用统计后可以获取缓存指标
stats := cache.Stats()
fmt.Printf("Hits: %d, Misses: %d, DelHits: %d, DelMisses: %d\n",
stats.Hits, stats.Misses, stats.DelHits, stats.DelMisses)
实际应用场景
- 会话存储:快速存取用户会话数据
- API响应缓存:缓存频繁请求的API结果
- 计算中间结果缓存:存储耗时计算的中间结果
与标准map和sync.Map对比
特性 | BigCache | sync.Map | 标准map |
---|---|---|---|
GC友好 | 是 | 部分 | 否 |
并发安全 | 是 | 是 | 否 |
大数据量 | 优 | 中 | 差 |
内存效率 | 高 | 中 | 高 |
复杂查询 | 简单 | 中等 | 灵活 |
注意事项
- BigCache不适合存储需要复杂查询的数据
- 值只能是[]byte类型,需要自行序列化
- 没有自动持久化功能,重启后数据会丢失
通过合理配置和使用BigCache,可以在Golang应用中高效处理GB级别的缓存数据,同时保持极低的GC压力和极高的吞吐量。