dot Redis 8 已发布——它是开源的

了解更多

更快的 Redis:客户端库支持客户端缓存

想要比 Redis 更快并非易事,但从今天起,您可以读取最常访问的数据,减少延迟,并更高效地使用资源。今天,我们自豪地宣布,官方 Redis 客户端库现已支持客户端缓存。

  • 用于 Java 编程语言的 Jedis
  • 用于 Python 编程语言的 Redis-py

Redis Community Edition 自版本 6 起就支持客户端缓存。但是,直到现在,您需要商业第三方客户端库才能使用此功能,因为 Redis 官方客户端库并未提供支持。现在,您可以直接使用 Redis 官方开源客户端库受益于近端缓存,只需几行代码,即可在建立连接时启用缓存。

让我们回顾一下什么是近端缓存以及使用它的动机,然后看看客户端缓存如何加速数据访问。

Redis 的客户端-服务器模型意味着性能受网络限制。每个操作都需要往返通信,这会影响性能,尤其是在高吞吐量系统或网络延迟成为问题时。

减少网络开销并提升应用程序性能的一种有效方法是使用客户端缓存,也称为近端缓存。这种技术允许频繁的读操作直接从客户端运行的同一应用服务器上的缓存中提供。启用客户端缓存后,客户端应用程序将使用后端应用程序缓存的数据,从而减少网络流量和延迟。

它的好处如下

  • 本地缓存非常适合读密集型场景、低带宽环境中的部署以及管理热点分片/键(用于读取)。
  • 它减少了到服务器的网络往返,有助于降低带宽消耗和成本——尤其是在云环境中。 
  • 服务器负载最小化,减少了计算开销并节省了基础设施成本。

工作原理

让我们通过一个例子来看看客户端缓存是如何工作的。

  1. SET foo bar
    1. 数据存储在服务器中
  2. GET foo
    1. 命令发送到服务器
    2. 客户端将回复缓存到本地内存中
  3. GET foo
    1. 客户端从本地内存获取 bar

无论何时,只要被跟踪的数据被任何客户端更改,服务器就会向所有当前跟踪该数据的客户端发布一条失效消息。 

  1. SET foo qux
    1. 客户端 A 更改数据
  2. 失效消息和缓存移除
    1. 客户端 B 在客户端建立并用于最初请求数据的同一连接上接收到一条失效消息
    2. 客户端 B 从缓存中移除数据 
  3. GET foo
    1. 客户端 B 再次请求数据
    2. 客户端 B 将回复缓存到本地内存中
  4. GET foo
    1. 客户端 B 从本地内存获取 qux

测试客户端缓存

要开始实验此功能,请记住客户端缓存需要 RESP3 协议,因为需要推送通知。  在设置连接时,请确保选择正确的协议版本。 

为了简化您在所有 Redis 产品上的开发体验,您需要 Redis CE 7.4、Redis Stack 7.4 或更新版本。您也可以测试最新的 Redis 8 M01 里程碑版本。客户端缓存与 Redis Software、Redis Cloud 以及 Azure Cache for Redis Enterprise 完全兼容,该功能目前在 Azure Cache for Redis Enterprise 中处于预览阶段,即将普遍可用。

我们说过只需几行代码即可轻松设置客户端缓存,这就是证明。下面的示例不会使您的客户端设置复杂化。只需在建立连接时启用缓存,如下面的 Python 示例所示,您就可以开始了。

r = redis.Redis(
protocol=3,
cache_config=CacheConfig(),
decode_responses=True
)

r.set("city", "New York")
cityNameAttempt1 = r.get("city") # Retrieved from Redis server and cached
cityNameAttempt2 = r.get("city") # Retrieved from cache

第一次检索键“city”时,它从数据库中读取并缓存到调用进程的内存中。后续读取将由本地缓存透明地提供服务,延迟极小,且不会增加数据库负载。 

如果您正在使用 Java,所有繁重的工作都由 Jedis 完成。您可以按如下方式创建连接并启用客户端缓存。

HostAndPort endpoint = new HostAndPort("localhost", 6379);
DefaultJedisClientConfig config = DefaultJedisClientConfig.builder().protocol(RedisProtocol.RESP3).build();
CacheConfig cacheConfig = CacheConfig.builder().maxSize(1000).build();
UnifiedJedis client = new UnifiedJedis(endpoint, config, cacheConfig);

Map<String, String> usr = new HashMap<>();
usr.put("id", "Johnny");
usr.put("first", "John");
usr.put("last", "Doe");
client.hset("session:e788eeb2", usr);
// Retrieved from Redis server and cached
client.hgetAll("session:e788eeb2"); 
// Retrieved from cache
client.hgetAll("session:e788eeb2"); 
// Peek into the cacheCache cache = client.getCache();
System.out.println(cache.getSize());
System.out.println(cache.getCacheEntries());
System.out.println(cache.getStats());

常见问题解答

客户端库是否支持连接池?

您可以为独立连接和连接池启用客户端缓存。它也适用于 Cluster 和 Sentinel API。

何时应该启用缓存?

每次缓存键的值在数据库中被修改时,Redis 都会向所有正在缓存该键的客户端推送一条失效消息。这会告诉客户端清除键的本地缓存值,因为该值已失效。这种行为意味着本地缓存命中和失效消息之间存在权衡:本地缓存命中率高于失效消息率的键是进行本地跟踪和缓存的最佳候选。 

例如,表示为字符串或嵌入在哈希中的计数器、排行榜等——像这样的键可以在标准连接上读取,以防止过多的失效消息。

如果我不想缓存某些键怎么办?

要控制哪些键被缓存,请实例化一个未启用客户端缓存的标准连接。

哪些数据被缓存?

客户端缓存发送到数据库的命令的规范化版本以及返回的结果。所有只读命令都会被缓存,除了

  • 概率和时间序列数据结构的命令
  • 搜索和查询命令
  • 非确定性命令(例如 HSCAN、ZRANDMEMBER 等)。

如何估算本地缓存的内存消耗?

缓存项大小不一,因此本地缓存的内存消耗与工作负载和存储数据的大小有关。客户端支持检查缓存,因此关于本地存储数据的相关统计信息可以支持基准测试。

如何验证缓存对我的命令是否有效?

如果您想了解幕后发生的情况,可以在 Redis Insight 中启动性能分析器以查看发送了哪些命令,或者在终端中使用 redis-cli 会话中的 MONITOR 命令。

使用客户端库

在此处阅读更多关于客户端缓存的信息,并使用下面的 GA 版本尝试您喜欢的客户端库。我们很快就会为其他语言的更多客户端库添加客户端缓存支持。

  • Jedis v5.2.0。请查阅 Jedis 特定的文档。
  • redis-py v5.1.1。请查阅 redis-py 特定的文档。