Redis 6采用新协议来实现客户端缓存功能

来自:开源中国(微信号:oschina2013),作者:局长

Redis 创始人兼核心开发者 antirez 在博客介绍了将在 Redis 6 提供的新功能 —— Client side caching(客户端缓存)

一年前,开发者 Ben Malec 在 Redis Conf 2018 上分享了它对客户端缓存功能的思考。Ben 对此有两个关键的想法,第一是使用 Redis 集群(Redis Cluster)中的“哈希槽(hash slots)”概念,以将 key 分成 16k 组。如此一来,客户端就无需追踪每个 key 的值,但可以为一组 key 使用单个元数据条目。另外就是,Ben 还使用了 Pub/Sub 机制以在 key 被修改时发送通知,不过这需要应用程序提供帮助。

antirez 也提到自己在大约一年前就已经考虑过 Redis 对客户端缓存(client side caching)功能的实现,并坚信这是 Redis 未来最重要的事情之一。当使用者需要进行快速存储或快速取操作时,就需要在客户端内存中存储一小部分信息,这是为了降低程序获取数据时的延迟。此功能在大规模的应用程序上十分重要,因为数据离应用程序越近,程序就能更快获取到数据。

antirez 表示全新的 Redis 协议 RESP3 将是 Redis 6 中最重要的特性,并解释了他为何要改进 Redis 协议,原因主要有两个,一是因为希望能为客户端提供更多的语义化回应(semantical replies),以开发使用旧协议难以实现的功能;另一个原因也是 antirez 认为最重要的一个,实现 Client side caching(客户端缓存)功能。这个功能十分常见,但 Redis 尚未提供。

受 Ben Malec 演讲的启发,antirez 开始了对 Redis 客户端缓存功能的初始设计:


因为 Ben 的解决方案没有使用来自服务器的任何帮助,这就会存在一些问题:

1.所有客户端都将收到有关所有哈希槽的失效消息。无论给定的客户端在此哈希槽中是否具有任何的 key
2.客户端必须在写入的同时发送显式的失效消息

所以 antirez 想到在服务器端的帮助下,可以创建一个协议。antirez 认为可以将大部分需要频繁存和取的数据直接放在服务器的内存中,以便让 Redis 为客户端完成部分工作,并使客户端缓存更简单、更有效。这个就是 Client side caching(客户端缓存)的概念。

不过这个思路有一个需要解决的问题是,如何控制数据的有效时间

在程序允许的情况下,虽然可以直接设置数据的有效时间,让数据在一段时间后失效。但 antirez 表示,大多数的应用程序无法接受提供过时的数据的风险,因此必须找到更理想的方案来控制数据的失效时间。

所以 antirez 决定开发新的协议 RESP3,在协议中加入新特性来支持客户端缓存功能,保证存储在客户端内存的数据,在收到来自服务器的失效通知时才失效

另外,当客户端和服务器的连接中断时,客户端无法接收到数据失效通知,这可能会导致服务出现问题。针对这种情况,一般的做法是重新建立客户端和服务器之间的连接,并更新客户端当前的缓存。

antirez 表示可以一直保持连接是最好的情况,但为了降低风险,Redis 服务器在与客户端断开连接时,会将失效通知发送给其他客户端。

这项名为"Client side caching"的功能尚未正式确定名字,最后可能会被命名为"Tracking"。而 antirez 已为 Redis 6 编写的代码目前只是被合并到 Redis unstable 分支中。

antirez 说到,为了打造更好的 Redis 协议,他为此编写了规范,然后再编写 RESP3 协议的代码,以及其他和 Redis 6 相关的内容,如 ACL 等。而客户端缓存功能也为 antirez 关于 Redis 的许多想法加入了巨大空间,不过最后 antirez 还是以某种方式放弃了,或者因为时间不够而放弃。

Redis 作者还表示在 Redis 6 候选版发布之前,这些功能都会进行调整,希望社区能积极反馈意见。由于 Client side caching 功能需要使用 RESP3 协议来支持实现,antirez 表示会想办法通过 RESP2 协议也能启用此功能。因为这只有在启用重定向时才有效,并且侦听消息的客户端应该进入 Pub/Sub 模式,这样就可以发送一些 Pub/Sub 消息。通过这种方式以完全重用旧客户端。

不过对于 Redis 6 这个重要的新功能,大家关注的重点似乎不再这里,oscer 纷纷表达了对红薯的开源项目 —— J2Cache 的担忧:


这位名为“nightmid”的用户的评论也值得我们思考:

“……这说明了一个方向性的问题,基于热门的软件开发的增强性的组件,很容易被软件本身扩展功能,而导致增强性的组件逐渐被替换掉,这是一个困局……”

红薯对此则表示内心毫无波动,甚至想马上发布一个新版本:

J2Cache 是基于内存和 Redis 的两级 Java 缓存框架,也是 OSChina 目前正在使用的两级缓存框架(要求至少 Java 8)。第一级缓存使用内存(同时支持 Ehcache 2.x、Ehcache 3.x 和 Caffeine),第二级缓存使用 Redis(推荐)/Memcached 。

由于大量的缓存读取会导致 L2 的网络成为整个系统的瓶颈,因此 L1 的目标是降低对 L2 的读取次数。该缓存框架主要用于集群环境中。单机也可使用,用于避免应用重启导致的缓存冷启动后对后端业务的冲击。

J2Cache 的两级缓存结构
L1:进程内缓存(caffeine\ehcache)
L2:Redis/Memcached 集中式缓存

数据读取
读取顺序 -> L1 -> L2 -> DB

数据更新
1.从数据库中读取最新数据,依次更新 L1 -> L2 ,发送广播清除某个缓存信息
2.接收到广播(手工清除缓存 & 一级缓存自动失效),从 L1 中清除指定的缓存信息

说了这么多,上码云给 J2Cache 点个 star 吧!
https://gitee.com/ld/J2Cache

推荐↓↓↓
数据库开发
上一篇:MySQL为什么建议使用自增主键 下一篇:这两个小技巧,让SQL语句不仅躲了坑,还提升了 1000 倍