示例代码
cache := zcache.NewCache()
// 注册加载器, 只有相同的 namespace 和 key 才会在加载数据时使用这个加载器
cache.RegisterLoader("test", "key", zcache.NewLoader(func(query zcache.IQuery) (interface{}, error) {
return "hello", nil
}))
var a string
_ = cache.Query("test", "key", &a) // 获取数据, 接收变量必须传入指针
fmt.Println(a)
结构图
流程图
获得
go get -u github.com/zlyuancn/zcache
支持的数据库
- 支持任何数据库, 本模块不关心用户如何加载数据
支持的缓存数据库
支持的编解码器
开发过程中不需要考虑每个对象的编解码, 可以在初始化时选择一个编解码器, 默认是
MsgPack
- 任何实现
codec.ICodec
的结构 - Byte
- Json
- JsonIterator
- MsgPack
- ProtoBuffer
如何解决缓存击穿
- 可以在启用SingleFlight, 当有多个进程同时获取一个相同的数据时, 只有一个进程会真的去加载函数读取数据, 其他的进程会等待该进程结束直接收到结果. 可以通过
core.ISingleFlight
接口实现分布式锁让多个实例同一时间只有一个进程加载同一个数据.
如何解决缓存雪崩
- 为加载器设置随机的TTL, 可以有效减小缓存雪崩的风险.
如何解决缓存穿透
- 我们提供了一个占位符, 如果在loader结果中返回
nil
, 我们会将它存入缓存, 当你在获取它的时候会收到错误errs.DataIsNil
- 在用户请求key的时候预判断它是否可能不存在, 比如判断id长度不等于32(uuid去掉横杠的长度)的请求直接返回数据不存在错误
注意: 在批量获取时如果某条数据是 nil
将会停止解码并返回 errs.DataIsNil
. 如果有好的建议请联系我们
benchmark
未模拟用户请求和db加载, 直接测试本模块本身的性能
go test -v -run "^$" -bench "^Benchmark.+$" -cpu 8,20,50,200,500 .
10 000 个key, 每个key 512字节随机数据, 请求key顺序随机
CPU: 4c8t 3.7GHz
# memory-cache
BenchmarkMemoryCache_10k-8 4167741 287 ns/op
BenchmarkMemoryCache_10k-20 3985488 308 ns/op
BenchmarkMemoryCache_10k-50 3968851 308 ns/op
BenchmarkMemoryCache_10k-200 3960068 320 ns/op
BenchmarkMemoryCache_10k-500 3601851 339 ns/op
BenchmarkRedisCache_10k-8 53870 21670 ns/op
BenchmarkRedisCache_10k-20 68161 17536 ns/op
BenchmarkRedisCache_10k-50 75562 16189 ns/op
BenchmarkRedisCache_10k-200 62276 18630 ns/op
BenchmarkRedisCache_10k-500 41538 28168 ns/op