有了“客户端缓存”的引入,Redis6对缓存有了理解。在上一篇介绍二级缓存的文章中,我们一共给出了4种实现方案。项目中整合了本地缓存Caffeine和远程缓存Redis,在只有单一远程缓存的基础上提升了应用的性能。一个等级。Hydra今天要和大家分享的技术和上面的二级缓存在思想上有些相似,但是只用Redis自带的server和client就可以实现,不需要借助其他本地缓存中间件。这是Redis6客户端缓存的一个新特性,可以让数据缓存在应用服务器和远程缓存中。介绍客户端缓存是Redis6众多新特性中比较实用的一个新特性。让我们看看官方文档来了解它的功能:客户端缓存是一种创建高性能服务的技术,可以使用应用服务器上的可用内存(这些服务器通常是不同于数据库服务器的节点),并且数据库中的一些信息直接存储在这些应用服务器上。与访问数据库等网络服务相比,访问本地内存所花费的时间要少得多,因此这种模式可以大大缩短应用程序获取数据的延迟,同时减轻数据库的负载压力。看到这里,我心想,这不和其他本地缓存如Guava、Caffeine一样吗?它只是使用的应用程序服务的内存。如果说有什么好处的话,可能是我可以在项目中少引入一个中间件。然而,在阅读了客户端缓存的具体应用模式后,我的浅薄猜想被彻底颠覆。两种模式了解了客户端缓存的基本功能后,我们来看看它的两种基本应用模式。Redis的客户端缓存支持称为跟踪。个人感觉keytracking的翻译比较容易理解。它有两种模式:默认模式,服务器会记录一个客户端具体访问了哪些键,当这些键对应的值发生变化时,会向这些客户端发送失效消息。这种模式会消耗服务器端的一些内存,但发送失效消息的范围仅限于客户端存储的密钥集。在广播模式下,服务器将不再记录客户端访问了哪些键,因此这种模式不会消耗服务器的内存。相反,客户端需要订阅键的特定前缀,每当与该前缀匹配的键对应的值发生变化时,客户端将收到通知消息。看到这里,是不是和我们之前使用的二级缓存有什么区别呢?如果你对二级缓存的架构不熟悉,可以先看看下图:这个架构在理论上看起来不错,但是在实践中需要注意的地方有很多,尤其是在分布式模式下,需要保证各个主机下一级缓存的一致性。回想一下我们原来的方案,我们可以利用redis本身的发布/订阅功能来实现:客户端缓存的出现大大简化了这个过程。我们以默认模式为例,看看使用客户端缓存后的运行过程:与原来的发布/订阅模式相比,我们可以看到明显的优势。使用客户端缓存功能后,我们只需要简单修改redis中的数据就可以了,完全可以省去手动处理发布/订阅消息的过程。优点这里,在了解了客户端缓存的基本功能和两种模式之后,我们来对比一下客户端缓存与传统使用redis做远程缓存以及集成二级缓存相比有哪些优势。当应用服务器端有缓存时,会直接读取本地缓存,可以减少网络访问带来的延迟,从而加快访问速度。同时也可以减少对redis服务器的访问次数,减轻redis的负载压力。在分布式环境下,不再需要通过发布订阅的方式通知其他主机更新本地缓存,保证数据的一致性。使用客户端缓存后,其原生的消息通知功能可以很好的支持本地缓存的失效,保证后续访问时可以获取更新的新数据。误解在我们开始演示客户端缓存的使用之前,让我们纠正一个误解。虽然这个新特性叫做客户端缓存,但是redis本身并没有提供在应用服务器端缓存数据的功能。这个功能必须由客户端访问redis本身来实现。说白了,redis服务器只负责通知你,你在应用服务本地缓存的key失效了。至于数据是如何缓存到本地的,redis不关心也不负责。功能演示下面将通过一些例子进行演示。运行本文代码的前提是你已经安装了Redis6.x版本。Linux环境下,直接从官网下载,编译安装即可。本文教你在Windows环境下运行Redis6.x。我们对概念性的东西也有了一个大概的了解。我们先来看看客户端缓存的三种具体实现方式(至于为什么还要多一种,后面会细说)。在正式开始之前,强烈建议大家花十分钟以上的时间了解一下Redis6的底层通信协议RESP3,否则看到具体的通信内容时可能会有一些疑惑。首先做一些准备工作,通过telnet连接redis服务,切换到resp3协议模式:telnet127.0.0.16379hello31.默认模式下,使用客户端连接redis服务后,需要开启trackingmodefunctionfirstthroughthecommand,因为在客户端连接后,这个选项默认是关闭的,你将收不到无效的推送消息:#Openclienttrackingon#Closeclienttrackingoff中启用跟踪时默认模式下,redis服务器会记录每个客户端请求的过期键,当键对应的值发生变化时,会向客户端发送失效消息。简单总结一下,就是说这个模式生效有两个必要的前提:开启追踪。客户端访问了某个密钥。接下来我们在telnet中模拟这个过程,分别启动两个redis客户端,先在client1中执行get命令,然后在client2中对同一个key执行set操作修改其值,然后在client1中进行一次push接收类型消息。RESP3中已经引入了push类型的消息,这里简单的写两句:>2$10invalidate*1$4userstartsfromthefirstbyte>表示消息是push类型的,下面的消息体包含两部分内容,第一部分表示接收到的报文类型为invalidate,即无效类型的信息,第二部分表示要失效的key为user。另外,当一个缓存的key由于过期时间过期,或者内存达到最大而采用逐出策略逐出时,也会向客户端发送PUSH消息。我们以缓存的key过期为例:另外,对于单个key,跟踪消息只会发送给客户端一次。第二次修改key对应的值后,客户端将不会再收到跟踪报文。信息。只有对这个key再次执行get命令,才会重新收到trackingmessage。默认模式虽然使用简单,但是需要在服务器端存储客户端的访问数据,记录哪些key被哪些客户端访问过。如果不是访问少量的热点数据,可能会占用redis服务器大量的内存空间。针对这种情况,可以试试下面介绍的广播方式。2、广播方式广播方式BCAST中,redis服务器不再记录key的访问情况,而是不分青红皂白地向所有启用跟踪广播的客户端发送消息。这样的好处是不需要浪费redis服务器的内存来记录,缺点是客户端可能会收到过多的消息,其中可能包含一些自己不需要的key。使用前需要通过命令开启广播模式:clienttrackingonbcast下面我们用一个例子来演示广播模式的使用:可以看到开启广播模式后,只要将值对应key在client2被修改,失效报文会在client1收到,不管client1之前本地是否缓存过。此外,与默认模式的另一个区别是,广播模式可以重复接收到一个密钥失效消息,因为服务器没有记录,所以只要修改一个密钥,客户端就会收到失效消息。这时候可能有朋友要问了,如果不想收到那么多无用的冗余消息,有没有办法过滤或者简化呢?答案是肯定的,在广播模式下,客户端只能关注某些前缀的key,也就是说我只需要接收这些前缀的key,其他的不用发给我。命令格式如下:clienttrackingonbcastprefixmyprefix下面看一个使用过程的例子:可以看到只设置前缀为order:的key后,就成功过滤了用户的失效报文出去。从这个角度来说,也要求我们在缓存一类数据时,使用同一个词作为前缀,规范了缓存中key的命名规则。至于在业务中使用哪种模型,可能需要更多的权衡。看看你能不能容忍在redis服务器上占用更多的内存,或者你能不能容忍接收到很多不必要的失效消息。3.转发模式默认模式和广播模式只有在启用RESP3协议的前提下才会生效。具体原因大家看完上面的例子应该就清楚了,因为要使用tracking就必须使用RESP3协议。新的推送消息类型。那么如果客户端还在使用老版本的RESPV2,想要体验这个功能,应该怎么修改呢?不得不说redis6的开发者还是想的挺全面的。为了适配RESPV2,他们专门设计了一种新的转发模式,允许使用旧版本协议的客户端通过Pub/Sub发布-订阅功能接收密钥过期信息。从上图可以看出,转发模式的核心是redis服务器将原始推送类型的跟踪信息转发给订阅_redis_:invalidate通道的指定客户端。我们把上面的过程梳理一下。首先需要在client1上使用命令开启转发模式:clienttrackingonbcastredirect[client-id]与广播模式相比,多了两个参数。redirect表示转发方式,后面的client-id表示将消息发送给哪个客户端,客户端id可以通过client2上的clientid命令获取。在client2中,需要订阅指定频道:subscribe_redis_:invalidate其实说白了,转发方式还是使用发布订阅功能,只是redis帮我们解放了双手,完成了发送消息的工作由我们自己。整个运行过程如下图所示:可以看出,client2中收到的消息格式与之前的推送类型消息不同。是RESPV2中多批回复格式的消息,消息的含义也是接收到的key。它已作废。需要注意的是,虽然命令中包含了一个bcast来开启转发模式,但它与广播模式有很大区别。在转发模式下,密钥失效报文只能转发给一个客户端。如果连续执行了两条指定的转发命令,后面执行的命令会覆盖前面命令转发的client-id。看到这里,是不是觉得这种转发模式有点鸡肋呢?毕竟实际业务场景中很可能会有多个client,只转发一个有点不太合理。不过也有可能是作者这样设计的,留下了一些瑕疵,让大家可以更快的拥抱RESP3……综上所述,客户端缓存的基础理论和使用介绍到这里就差不多了。不得不说,Redis6的这一项新特性,着实给了我们眼前一亮的感觉。从这个新特性也可以看出,Redis具有将缓存从服务器的限制中解放出来,导向客户端,统一缓存的意义。但是,这个过程应该不简单。前面我们说了,毕竟只有Redis服务端是不够的,还需要一个优秀的客户端来支撑。那么在下一篇文章中,我们就从实际的角度来看一下如何改造客户端,让客户端缓存在项目中开花结果。本次分享就到这里,我是Hydra,下篇文章见。官方文档:https://redis.io/docs/manual/client-side-caching/。
