3 个不稳定版本
0.2.1 | 2024年3月5日 |
---|---|
0.2.0 | 2024年3月5日 |
0.1.0 | 2023年11月26日 |
#166 in 缓存
70KB
1K SLoC
groupcache
这是将一个流行的分布式缓存库从 Go groupcache 转移到 Rust 的实现。
groupcache 是一个分布式缓存和缓存填充库,在很多情况下可作为 memcached 节点池的替代品。它通过键进行分片以选择哪个节点负责该键。
与原始实现比较
- 使用 Rust 实现,因此速度非常快。但实际上,我还没有进行过任何严肃的基准测试。
- 没有实现分组(这使得我怀疑 groupcache 的名字是否仍然有意义)。
- 如果需要这样的功能,可以通过在库的顶部实现不同的
ValueLoader
实现,根据键前缀来实现。 - 然而,在这种情况下,所有指标都会一起汇总,并且无法针对每个组进行缓存定制。这可能是未来版本中需要考虑的事情。
- 如果需要这样的功能,可以通过在库的顶部实现不同的
- 内置服务发现机制
pull-通过 ServiceDiscovery 特性实现
- 基于推送的 API
- 支持缓存失效
- 必须小心处理来自
hot_cache
的过时值,请参阅GroupcacheBuilder
的文档。
- 必须小心处理来自
与 memcached 的比较(来自原始仓库)
与 memcached 一样,groupcache
通过键进行分片以选择哪个节点负责该键。与 memcached 不同,groupcache
-
不需要运行一组单独的服务器,从而大幅减少了部署/配置的痛苦。groupcache 既是客户端库也是服务器。它连接到自己的节点,形成一个分布式缓存。
-
还提供缓存填充机制。而 memcached 只会说“抱歉,缓存未命中”,通常会导致来自无界数量的客户端(这已导致几次有趣的故障)的数据库(或任何其他)负载,而 groupcache 协调缓存填充,以确保整个复制进程集中只有一个进程加载缓存,然后将加载的值多路复用到所有调用者。
-
不支持版本化值。如果键
"foo"
的值是"bar"
,则键"foo"
必须始终是"bar"
。没有缓存过期时间,也没有显式缓存淘汰。因此,也没有 CAS(比较并交换)操作,也没有增量/减量操作。这也意味着 groupcache... -
...支持将超级热项自动镜像到多个进程中。这可以防止因非常流行的键/值而导致的 memcached 热点问题,即机器的 CPU 和/或 NIC 被过载。
-
目前仅适用于 Go。我不太可能将其代码移植到任何其他语言。
加载过程
简而言之,对 Get("foo")
的 groupcache 查找过程如下
(在运行相同代码的 N 台机器中的一台机器 #5 上)
-
"foo"
的值是否在本地内存中,因为它是超级热项?如果是,则使用它。 -
"foo"
的值是否在本地内存中,因为 peer#5
(当前 peer)是它的所有者?如果是,则使用它。 -
在我的一组 N 个 peer 中,我是键
"foo"
的所有者吗?(例如,它是否一致性哈希到 5?)如果是,则加载它。如果有其他调用者通过相同的进程或通过来自 peers 的 RPC 请求进入,它们将阻塞等待加载完成并获得相同的答案。如果不是,则 RPC 到所有者的 peer 并获取答案。如果 RPC 失败,则直接在本地加载(仍然带有本地重复抑制)。
示例
simple
- 展示了 groupcache 如何去重并发请求。simple-multiple-instances
- 展示了 groupcache 如何与多个实例连接。kubernetes-service-discovery
- 展示了如何在 k8s 上部署简单的 axum 服务器的同时运行 groupcache。服务发现通过集成 Kubernetes API 服务器来处理。
文档
请参阅 https://docs.rs/groupcache 和 https://docs.rs/groupcache/latest/groupcache/struct.Groupcache.html
依赖关系
~12–21MB
~284K SLoC