dgraph-io/ristretto

GitHub: dgraph-io/ristretto

Ristretto 是一款高性能、支持完全并发的 Go 内存缓存库,通过 TinyLFU 准入与 SampledLFU 驱逐策略实现行业领先的缓存命中率。

Stars: 6967 | Forks: 444

# Ristretto [![GitHub 许可证](https://img.shields.io/github/license/dgraph-io/ristretto)](https://github.com/dgraph-io/ristretto?tab=Apache-2.0-1-ov-file#readme) [![GitHub 仓库星标](https://img.shields.io/github/stars/dgraph-io/ristretto)](https://github.com/dgraph-io/ristretto/stargazers) [![GitHub 提交活跃度](https://img.shields.io/github/commit-activity/m/dgraph-io/ristretto)](https://github.com/dgraph-io/ristretto/commits/main/) [![Go 报告卡](https://img.shields.io/badge/go%20report-A%2B-brightgreen)](https://goreportcard.com/report/github.com/dgraph-io/ristretto) Ristretto 是一个快速、并发的缓存库,其构建重点是性能和正确性。 构建 Ristretto 的动机来自于 [Dgraph][] 中对无竞争缓存的需求。 ## 功能 - **高命中率** - 得益于我们独特的准入/驱逐策略组合,Ristretto 的性能是同类中最好的。 - **驱逐:SampledLFU** - 与精确的 LRU 相当,并且在搜索和数据库跟踪记录上具有更好的性能。 - **准入:TinyLFU** - 以极小的内存开销(每个计数器 12 位)带来额外的性能提升。 - **高吞吐量** - 我们使用了多种技术来管理竞争,从而实现了出色的吞吐量。 - **基于成本的驱逐** - 任何被认为有价值的大型新项都可以驱逐多个较小的项(成本可以是任何东西)。 - **完全并发** - 你可以根据需要使用任意数量的 goroutine,而吞吐量几乎不会下降。 - **指标** - 用于吞吐量、命中率和其他统计数据的可选性能指标。 - **简单的 API** - 只需找出你理想的 `Config` 值,你就可以开始使用了。 ## 状态 Ristretto 已达到生产就绪状态。请参阅[使用 Ristretto 的项目](#projects-using-ristretto)。 ## 快速开始 ### 安装 要开始使用 Ristretto,请安装 Go 1.21 或更高版本。Ristretto 需要 go modules。在你的项目中,运行以下命令: ``` go get github.com/dgraph-io/ristretto/v2 ``` 这将获取该库。 #### 选择版本 请遵循以下规则: - v1.x.x 是大多数具有 Ristretto 依赖的程序中使用的第一个版本。 - v2.x.x 是支持泛型的新版本,因此它具有稍微不同的接口。此版本旨在解决使用旧版本 Ristretto 的程序的兼容性问题。如果你开始编写新程序,建议使用此版本。 ## 用法 ``` package main import ( "fmt" "github.com/dgraph-io/ristretto/v2" ) func main() { cache, err := ristretto.NewCache(&ristretto.Config[string, string]{ NumCounters: 1e7, // number of keys to track frequency of (10M). MaxCost: 1 << 30, // maximum cost of cache (1GB). BufferItems: 64, // number of keys per Get buffer. }) if err != nil { panic(err) } defer cache.Close() // set a value with a cost of 1 cache.Set("key", "value", 1) // wait for value to pass through buffers cache.Wait() // get value from cache value, found := cache.Get("key") if !found { panic("missing value") } fmt.Println(value) // del value from cache cache.Del("key") } ``` ## 基准测试 这些基准测试可以在 https://github.com/dgraph-io/dgraph-benchmarks/tree/main/cachebench/ristretto 中找到。 ### 搜索的命中率 此跟踪记录被描述为“大型商业搜索引擎为响应各种网络搜索请求而发起的磁盘读取访问。”

Graph showing hit ratios comparison for search workload

### 数据库的命中率 此跟踪记录被描述为“一个商业站点的数据库服务器,在商业数据库之上运行 ERP 应用程序。”

Graph showing hit ratios comparison for database workload

### 循环的命中率 此跟踪记录展示了一种循环访问模式。

Graph showing hit ratios comparison for looping access pattern

### CODASYL 的命中率 此跟踪记录被描述为“一小时内对 CODASYL 数据库的引用。”

Graph showing hit ratios comparison for CODASYL workload

### 混合工作负载的吞吐量

Graph showing throughput comparison for mixed workload

### 读取工作负载的吞吐量

Graph showing throughput comparison for read workload

### 写入工作负载的吞吐量

Graph showing throughput comparison for write workload

## 使用 Ristretto 的项目 以下是已知的、使用 Ristretto 的项目列表: - [Badger](https://github.com/dgraph-io/badger) - Go 中的内嵌式 key-value 数据库 - [Dgraph](https://github.com/dgraph-io/dgraph) - 具有图后端的水平可扩展且分布式的 GraphQL 数据库 ## 常见问题 ### 你们是如何实现这种性能的?你们采取了哪些捷径? 我们在 [Ristretto 博客文章](https://web.archive.org/web/20250806164019/https://hypermode.com/blog/introducing-ristretto-high-perf-go-cache) 中进行了详细说明,但简而言之:我们的吞吐量性能归功于批处理和最终一致性的结合。我们的命中率性能主要归功于出色的[准入策略](https://arxiv.org/abs/1512.00727)和 SampledLFU 驱逐策略。 至于“捷径”,Ristretto 所做的唯一一件可能被理解为捷径的事情就是丢弃部分 Set 调用。这意味着对新项的 Set 调用(更新是有保证的)并不保证一定会进入缓存。新项可能会在两个节点被丢弃:在通过 Set 缓冲区时,或者在通过准入策略时。然而,这根本不会对命中率产生太大影响,因为我们预期最受欢迎的项会被 Set 多次,并最终进入缓存。 ### Ristretto 是分布式的吗? 不,它就像任何其他 Go 库一样,你可以将其导入到你的项目中并在单个进程内使用。
标签:EVTX分析, Go, Ruby工具, 内存管理, 并发编程, 开发组件库, 日志审计, 缓存