我尝试对Go的Cache包进行了基准测试的经历
这篇帖子是Go4 Advent Calendar 2019第15天的内容。
晚上好!天气渐渐变冷了呢。
嗯,我们平时经常使用GCP。过一段时间会产生大量未被使用的资源,这给成本带来了压力。
在成本控制和库存工作中,我们想要找到没有进行生命周期设置或因各种原因很难设置,且未使用的磁盘。虽然aws cli有一个命令可以找到这些磁盘,但goolgle-cloud-sdk的gcloud命令没有。因此,我们决定自己创建这个命令。
https://github.com/k-oguma/gce-available-disks
在那个时候,作为一个选项,我们设定了在Stackdriver日志中搜索活动日志,以便能够确定是谁创建了该活动日志(保存期限很短)。
然而,在GCP项目中产生大量活动日志的场景下,搜索速度较慢。
另外也有讨论,可以首先投入到Bigquery中,类似AWS Athena的方式可能更好,但并不是所有项目都是如此,并且为了通用性且开源,我们选择使用本地缓存的方法。
因为这样的原因,我想使用 Go 的缓存,所以决定进行一些缓存包的性能测试。
这是我第一次使用 Go 的缓存包。
在这里,所谓的缓存是指本地缓存。
另外,在这次验证中,我们将保持原始设置而不进行任何调整。
验证环境
-
- macOS Mojave v10.14.6
-
- iMac 27 inch Retina 5K 27-inch, 2017
-
- CPU 3.5GHz Intel Core i5
-
- Memory 24GB DDR4
- Fusion drive 1TB
尝试过的包裹
我已经尝试了以下三种选项。
-
- akyoto/cache
-
- patrickmn/go-cache
- eko/gocache
在这些选项中,eko/gocache 是一个特殊的Go缓存库,其概念是使其能够与各种缓存机制进行集成。这与”go build”的环境变量GOCACHE无关。
eko/gocache的补充说明
在上述的三种选择中,eko/gocache 是通过采用现有元素进行开发的风格。
-
- Built-in stores
Memory (bigcache) (allegro/bigcache)
Memory (ristretto) (dgraph-io/ristretto)
Memcache (bradfitz/memcache)
Redis (go-redis/redis)
More to come soon
我希望在这些选项中使用 bigcache 和 ristretto 进行本地缓存和验证。
注意事项的主题是gocache
在这里面,有一个最显著的特点。
-
- import する際は、pathに注意してください
github.com/eko/gocache ではなく、 github.com/eko/gocache/cache などになります。
waitを入れないと実行で出来ません
time.Sleep(10 * time.Millisecond)
关于Bigcache
Bigcache是一个能够高速处理GB级别缓存大小的缓存系统。为了提高性能,Bigcache使用了一些技巧来避免使用sync.RWMutex等会阻塞写入的并发处理方式,并通过使用分片来合理分散并避免协程阻塞。选择使用分片的原因是当分片数量较多,且哈希函数能够将唯一键均匀分布时,竞争锁的冲突几乎可以最小化到零。此外,Bigcache还通过FIFO和时间戳比较的方式轻松地清除过时缓存,避免了对缓存条目执行垃圾回收操作,从而降低了延迟。详细内容请参考以下链接:
https://awesomeopensource.com/project/allegro/bigcache
https://allegro.tech/2016/03/writing-fast-cache-service-in-go.html
https://github.com/allegro/bigcache
意译:将以下内容以中文本地语言进行意译,只需提供一种选项:
当我们开始开发时,Go 1.6还处于RC阶段。我们最初采取的措施是将代码更新至最新的RC版本,以缩短请求处理时间。然而,在我们的情况下,性能几乎相同。于是我们开始寻找更高效的解决方案,并找到了fasthttp。这是一个提供零分配的HTTP服务器库。根据文档,综合测试显示它的速度是标准HTTP处理程序的10倍。尽管在我们的测试中,它只有1.5倍的提速,但仍然表现卓越!
关于所提到的 fasthttp,据公司验证,它已经经过验证,并且大大减少了内存分配,速度也得到了提升,验证结果展现出良好的性能。
关于Ristretto
对于Ristretto,似乎具有以下特点。
重点放在性能和准确性上的开发需求,使用Dgraph(一个可水平扩展的开源图数据库,支持类似GraphQL的查询语言,并支持Protocol Buffers通过GRPC和HTTP进行通信)开发了一个无竞争的缓存。
https://github.com/dgraph-io/benchmarks/tree/master/cachebench/ristretto
https://blog.dgraph.io/post/introducing-ristretto-high-perf-go-cache/

那么实际结果如何呢?我决定试一试这些方法。
我创建了一个用于测试的仓库。
我创建了类似于https://github.com/k-oguma/go-cache-benchmarks的东西。
测量规则和流程如下所示。
-
- 最初先执行内存flush操作。
由于不是共享内存,所以只需在首次执行即可。
在以下每个软件包的默认设置下进行相同内容的基准测试:
akyoto/cache
patrickmn/go-cache
在eko/gocache中的以下两个:
Bigcache
Ristretto
执行一字符的Cache Set和Get操作,以及Delete操作的测量。
执行长文本内容的Cache Set和Get操作,以及Delete操作的测量。
我们将根据上述的测量内容进行实际测量。
请确保这些都能进行Set和Get操作。
由于gocache有些特殊,请参考已注释的内容。
用法
帮助
make help
进行基准测试
make test
结果
% make test
Benchmark target: /Users/katsuyuki/go/src/github.com/k-oguma/go-cache-benchmarks/cache
goos: darwin
goarch: amd64
pkg: github.com/k-oguma/go-cache-benchmarks/cache
BenchmarkAppend_CacheEveryTime-4 560948 1919 ns/op 744 B/op 15 allocs/op
BenchmarkAppend_CacheForLargeStringsEveryTime-4 634150 2236 ns/op 744 B/op 15 allocs/op
PASS
ok github.com/k-oguma/go-cache-benchmarks/cache 2.546s
----------------------
Benchmark target: /Users/katsuyuki/go/src/github.com/k-oguma/go-cache-benchmarks/go-cache
goos: darwin
goarch: amd64
pkg: github.com/k-oguma/go-cache-benchmarks/go-cache
BenchmarkAppend_CacheEveryTime-4 379837 3836 ns/op 909 B/op 11 allocs/op
BenchmarkAppend_CacheForLargeStringsEveryTime-4 222919 4854 ns/op 913 B/op 11 allocs/op
PASS
ok github.com/k-oguma/go-cache-benchmarks/go-cache 2.717s
----------------------
Benchmark target: /Users/katsuyuki/go/src/github.com/k-oguma/go-cache-benchmarks/gocache
goos: darwin
goarch: amd64
pkg: github.com/k-oguma/go-cache-benchmarks/gocache
BenchmarkAppend_CacheEveryTimeForBigcache-4 62 39577989 ns/op 337197180 B/op 11301 allocs/op
BenchmarkAppend_CacheForLargeStringsEveryTimeForBigcache-4 36 37570676 ns/op 337200235 B/op 11302 allocs/op
BenchmarkAppend_CacheEveryTimeForRistretto-4 74 15981556 ns/op 50624497 B/op 548 allocs/op
BenchmarkAppend_CacheForLargeStringsEveryTimeForRistretto-4 76 15482215 ns/op 50625023 B/op 548 allocs/op
PASS
ok github.com/k-oguma/go-cache-benchmarks/gocache 6.365s
----------------------


结果出乎意料。这次是使用默认设置进行的,并未进行任何调整,因此结果可能会有所变化。此外,gocache有一些特性,但同时也内置了各种缓存包,因此可以像链式缓存那样进行缓存的连结,似乎朝着更高功能的方向发展。
在https://github.com/k-oguma/gce-available-disks上,我已决定使用go-cache。
如果你知道其他类似的Go缓存实现方式或者有推荐的Go缓存包,麻烦告诉我一声,我会非常感激。
另外,我也想要亲自研究一下并尝试自己去制作。
明天将是mergit先生的文章!