Golang Go语言高性能缓存Theine v0.5.0发布, Zero Allocation & 读取速度大幅优化

发布于 1周前 作者 nodeper 来自 Go语言

https://github.com/Yiling-J/theine-go

直接放上最新的 100% read/write throughput benchmark 结果,其他比例以及缓存命中率可以看 Readme:

100% read (cpu 8/16/32)

goos: linux
goarch: amd64
pkg: github.com/maypok86/benchmarks/throughput
cpu: Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz

BenchmarkCache/zipf_otter_reads=100%,writes=0%-8 88954334 14.78 ns/op 67648151 ops/s BenchmarkCache/zipf_theine_reads=100%,writes=0%-8 51908306 21.87 ns/op 45729075 ops/s BenchmarkCache/zipf_ristretto_reads=100%,writes=0%-8 27217994 42.36 ns/op 23606992 ops/s

BenchmarkCache/zipf_otter_reads=100%,writes=0%-16 132372591 8.397 ns/op 119086508 ops/s BenchmarkCache/zipf_theine_reads=100%,writes=0%-16 85420364 13.78 ns/op 72549558 ops/s BenchmarkCache/zipf_ristretto_reads=100%,writes=0%-16 47790158 25.17 ns/op 39734070 ops/s

BenchmarkCache/zipf_otter_reads=100%,writes=0%-32 174121321 7.078 ns/op 141273879 ops/s BenchmarkCache/zipf_theine_reads=100%,writes=0%-32 118185849 10.45 ns/op 95703790 ops/s BenchmarkCache/zipf_ristretto_reads=100%,writes=0%-32 66458452 18.85 ns/op 53055079 ops/s

100% write (cpu 8/16/32)

goos: linux
goarch: amd64
pkg: github.com/maypok86/benchmarks/throughput
cpu: Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz

BenchmarkCache/zipf_otter_reads=0%,writes=100%-8 1567917 723.0 ns/op 1383080 ops/s BenchmarkCache/zipf_theine_reads=0%,writes=100%-8 2194747 542.4 ns/op 1843615 ops/s BenchmarkCache/zipf_ristretto_reads=0%,writes=100%-8 1839237 642.5 ns/op 1556503 ops/s

BenchmarkCache/zipf_otter_reads=0%,writes=100%-16 1384345 846.0 ns/op 1181980 ops/s BenchmarkCache/zipf_theine_reads=0%,writes=100%-16 1915946 528.8 ns/op 1891008 ops/s BenchmarkCache/zipf_ristretto_reads=0%,writes=100%-16 1765465 697.3 ns/op 1434089 ops/s

BenchmarkCache/zipf_otter_reads=0%,writes=100%-32 1265883 979.8 ns/op 1020607 ops/s BenchmarkCache/zipf_theine_reads=0%,writes=100%-32 1953358 526.1 ns/op 1900935 ops/s BenchmarkCache/zipf_ristretto_reads=0%,writes=100%-32 1618098 696.1 ns/op 1436625 ops/s

benchmem 100% write (cpu 32)

goos: linux
goarch: amd64
pkg: github.com/maypok86/benchmarks/throughput
cpu: Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz

BenchmarkCache/zipf_otter_reads=0%,writes=100%-32 80 B/op 1 allocs/op BenchmarkCache/zipf_theine_reads=0%,writes=100%-32 0 B/op 0 allocs/op BenchmarkCache/zipf_ristretto_reads=0%,writes=100%-32 112 B/op 3 allocs/op

如果你还在用 Ristretto 个人建议换成 Theine 或者 Otter ,Ristretto 和你想的可能不太一样:

  • Ristretto 的写入操作是异步的,不能写入完立刻读取。
  • Ristretto 的写入有一定随机性,为了提高写速度 Ristretto 使用了 select/default 把数据写入 channel ,导致数据可能丢失。把 default 去掉写入速度会大幅下降。
  • Ristretto 的 Cost 参数默认情况下不 work ,导致 Ristretto 实际存储的数据量可能远低于你想要的数据量,需要手工把IgnoreInternalCost设为 true ,但这个参数在 Readme 里完全没有提到。
  • 读写高并发下 Ristretto 有比较严重的 contention ,75% Read 下速度大约是 Theine/Otter 的 1/4 ,这还是丢失部分写入的情况下。

Golang Go语言高性能缓存Theine v0.5.0发布, Zero Allocation & 读取速度大幅优化

更多关于Golang Go语言高性能缓存Theine v0.5.0发布, Zero Allocation & 读取速度大幅优化的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

再附加一个: Ristretto 不会在 cache 里保存你的 key ,而是计算两个 hash 用作 key, 虽然几率很低但理论上有可能发生碰撞。而且这种方法也导致 Ristretto 无法添加 Range 或者 Callback 之类的 API ,因为完全没有存真实的 key

更多关于Golang Go语言高性能缓存Theine v0.5.0发布, Zero Allocation & 读取速度大幅优化的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Ristretto 这个 select/default 有点难崩, 还不如去掉 chan 异步直接执行, 嫌弃锁范围大同步竞争浪费必须并发的话可以考虑另一种方式: 用 chan 做 trigger, 只有 queue head 时才 trigger 写协程并且 trigger 单次处理完当前所有, pop push 各自粒度的锁
两个 hash 用作 key 是图什么, 避免大 key 的浪费, 或者用固定的[N]byte 避免指针类型的 gc item 数量?

> 两个 hash 用作 key 是图什么, 避免大 key 的浪费, 或者用固定的[N]byte 避免指针类型的 gc item 数量?

关键是, 这样就不好去做非精确 key 相关的了, 比如遍历 list 之类的

避免大 key ,不过 Ristretto 的第一版只用了 1 个 hash: https://github.com/dgraph-io/ristretto/issues/30 。在 Theine 里就用的类似 chan 做 trigger 的方法,当 write chan 收到数据时继续尝试额外获取 N 个数据,没有就直接返回。高写入并发下能批量处理,低并发下也能保持时效性:

for first := range s.writeChan {
s.writeBuffer = append(s.writeBuffer, first)
loop:
for i := 0; i < WriteBufferSize-1; i++ {
select {
case item, ok := <-s.writeChan:
s.writeBuffer = append(s.writeBuffer, item)
default:
break loop
}
}
}

我的一些协程池为了减少常驻协程数量, 也是类似的, 但不用 chan 了, 只是 queue head go func 里批量处理所有然后退出, 不是 head 就 push

chan 在性能场景确实挺贵的

针对“Golang Go语言高性能缓存Theine v0.5.0发布,Zero Allocation & 读取速度大幅优化”的帖子,作为IT领域Go语言方面的专家,以下是我的回复:

Theine v0.5.0版本的发布标志着Go语言高性能缓存技术取得了显著进步。该版本实现了Zero Allocation(零分配)特性,这一核心优化策略在减少内存使用和提高程序性能方面发挥着关键作用。

Zero Allocation通过避免不必要的内存分配,显著降低了程序的内存占用。在缓存服务中,这通常意味着更少的内存浪费和更高的缓存命中率,从而提升整体性能。此外,Theine v0.5.0还针对读取速度进行了大幅优化,使得数据访问更加迅速,进一步提高了缓存服务的响应速度。

这些优化特性使得Theine v0.5.0成为构建高性能、低延迟Go语言应用程序的理想选择。对于需要频繁访问和快速响应的场景,如在线游戏、实时数据处理等,Theine的高性能缓存服务将带来显著的性能提升和用户体验优化。

综上所述,Theine v0.5.0的发布无疑是Go语言高性能缓存技术的一个重要里程碑,值得广大开发者关注和尝试。

回到顶部