Redis 6.0的新特性也是在一步步的讨论和优化中肯定的。redis
不少的特性已经在以前的RC等版本中介绍过了。数据库
可是正式GA版中也有一些新的变化:缓存
@antirez 提到只是Redis历史上最大的一次版本更新,因此谨慎建议在应用的产品中仍是多多测试评估,而且承诺一旦遇到大的bug就会紧急发布6.0.1版。果不其然,一天后就发布了 6.0.1版,修复了一个allocator的bug,这个bug是为了优化而引入的,如今暂时去掉了。多线程
I just released Redis 6.0.1. Unfortunately there was a bug in Redis 6.0.0 introduced just a few days before the release, that only happens when using the non-default allocator (libc malloc in this case triggers it). Optimization reverted, 6.0.1 released. Sorry for the issue.app
本文主要关注Client side caching(客户端缓存)这一特性。less
smallnest/RESP3 是Redis RESP3协议的解析库,你可使用它和Redis底层通信,或者包装它实现新版的Redis client库或者Redis Server端。ide
一年前,当 @antirez 参加完纽约Redis大会后,5:30就在旅店中醒来了,面对曼哈顿街头的美丽景色,在芸芸众生中思索Redis的将来。包括客户端缓存。memcached
其实,客户端缓存特性是收到Redis Conf 2018的Ben Malec的影响,一会儿打开了 @antirez 思路。咱们知道, 不少公司使用Redis作缓存系统,而且很好的提升了数据访问的性能,可是不少企业为了进一步应对热点数据,仍是会在redis的client端缓存一部分热点数据,用来应对吃瓜事件。好比在微博咱们常常遇到的是明星出轨、明星分分合合、突发事件等等,每一年都会有几回突发的事件,微博除了使用Redis作缓存避免直接访问数据库,还会在前面加更多的cache层,好比L1 cache
等,采用memcached等产品做为热数据的缓存。那么就有一个问题,如何可以及时的同步这些cache和redis的数据呢?Ben提供了很是有意思的想法。oop
伫立在曼哈顿的街头,@antirez 陷入了沉思,后来回到旅馆他开始实现第一版的客户端的缓存。固然,最终Redis 6.0中实现和这个第一版的实现差异很大,可是非常显然,从客户端的演化过程当中咱们仍是能看到@antirez对这个特性所在的权衡(trade off)。关于这个历史本文不作太多的介绍,由于咱们更关注于这个特性最终是什么样子的。性能
Redis实现的是一个服务端协助的客户端缓存,叫作tracking
。客户端缓存的命令是:
CLIENT TRACKING ON|OFF [REDIRECT client-id] [PREFIX prefix] [BCAST] [OPTIN] [OPTOUT] [NOLOOP]
当tracking
开启时, Redis会"记住"每一个客户端请求的key,当key的值发现变化时会发送失效信息给客户端(invalidation message)。失效信息能够经过RESP3协议发送给请求的客户端,或者转发给一个不一样的链接(支持RESP2+ Pub/Sub)。当广播模式(broadcasting)开启时,参与tracking
的客户端会收到它经过前缀订阅的key的相关的通知,即便它没请求过对应的key。同时还提供了OPTIN
、OPTOUT
等模式。
失效消息:当一个key的数据有修改的时候,须要告诉客户端它之前缓存的数据失效了,这时redis会主动发送一条失效消息
tracking
。在这种模式下客户端须要设置将track的key的前缀,这些key的失效消息会广播给全部参与的客户端,无论这些客户端是否请求/缓存额这些key。不开始广播模式时,Redis只会track那些只读命令请求的key,而且只会报告一次失效消息。CLIENT CACHING yes
以后被调用。CLIENT CACHING off
以后被调用。下面让咱们一一介绍每一个选项。
首先让咱们介绍RESP3协议相关的选项,REDIRECT <id>
放在最后介绍。
在尝试以前,你首先须要安装一个redis 6.x的版本,目前时6.0.1。在官方网站上有源代码的下载,编译安装也很简单:
make distclean make make test sudo make install
相信很快就有编译好的二进制包能够下载。
启动server, 它会在6379端口启动一个服务:
redis-server
使用redis-cli
访问,默认访问本机的6379实例:
redis-cli
固然你能够经过-h
查看额外的参数配置,好比使用其它端口等等,这里咱们使用最简单的例子,重点是了解客户端缓存的特性。
有时候为了更好的观察redis的返回结果,咱们使用telnet
而不是redis-cli
做为client链接redis,由于redis-cli对结果作了处理,尤为是失效消息,你可能没法观测到。
client tracking on
)启动redis server:
启动redis-cli:
固然,咱们使用telnet来测试,方便观察redis的返回结果,刚才redis-cli用来更新key值,辅助测试。链接上以后发送hello 3
开启RESP3协议:
➜ ~ telnet localhost 6379 Trying ::1... Connected to localhost. Escape character is '^]'. hello 3 %7 $6 server $5 redis $7 version $5 6.0.1 ......
以后尝试开启tracking
并读取a
的值:
client tracking on +OK set a 1 +OK get a $1 1
这个时候若是使用redis-cli做为另一个client更新a
的值,telnet这个client应该能得到通知:
127.0.0.1:6379> set a 2 OK
观察telnet,它收到了一个失效消息:
>2 $10 invalidate *1 $1 a
注意它采用RESP3中的PUSH类型(>
)。
若是这个使用你再使用redis-cli更新a
的值,telnet不会再收到失效消息。除非telnet client再get a
一次,从新tracking
a的值。
能够随时取消tracking
:
client tracking off
client tracking on
)上面的方式会tracking全部的key,若是你只想跟踪特定的key, 目前redis提供了一种方式,也就是前缀匹配的方式。你能够只tracking特定前缀的key。它只应用了广播模式。
使用telnet client设定前缀和开启tracking:
hello 3 ....... client tracking on prefix a bcast +OK client tracking on prefix user bcast +OK
咱们tracking两个前缀,以a
开头的全部的key和以user
开头的全部的key,全部a
开头的全部的key和以user
开头的全部的key(包括a
和user
)的key变更时它应该都收到消息。
而后咱们使用redis-cli更新三个key: abc
、user:32432723213
和feed:6532343243432
:
127.0.0.1:6379> set abc 100 OK 127.0.0.1:6379> set user:32432723213 good OK 127.0.0.1:6379> set feed:6532343243432 abc OK
telnet client收到abc
和user:32432723213
的失效消息,而不会收到feed:6532343243432
的失效消息:
>2 $10 invalidate *1 $3 abc >2 $10 invalidate *1 $16 user:32432723213
你能够经过client tracking off
中止客户端缓存。目前貌似不能只中止对单个的前缀的tracking
。即便你使用client tracking off prefix user
也是取消对全部的key的tracking
。
...... } else if (!strcasecmp(c->argv[2]->ptr,"off")) { disableTracking(c); } else { ......
若是使用OPTIN
,能够有选择的开启tracking
。只有你发送client caching yes
以后的下一条的只读命令的key才会tracking
, 不然其它的只读命令中的key不会tracking。
首先咱们开始optin
,读取a的值,这个时候使用redis-cli client修改a的值为1000,咱们并无收到a
的失效消息。
client tracking on optin +OK get a $1 2
接下来咱们发送client caching yes
,紧接着获取a的值,这个时候若是再修改a的值,你就能够收到一条a的失效消息:
client caching yes +OK get a $4 1000 >2 $10 invalidate *1 $1 a
必须是紧跟着client caching yes
吗?是的,好比发送下面的命令,只会tracking
b,而不是a:
client caching yes +OK get b _ get a $4 2000
若是使用OPTOUT
,你也能够有选择的退出tracking
。只有你发送client caching off
以后的下一条的只读命令的key才会中止tracking
, 不然其它的只读命令中的key都会被tracking。
能够看到它和OPTIN
正好相反,你能够根据你的场景来选择。
好比下面的例子,开启OPTOUT
以后,对任意的key的变更都收到失效消息:
client tracking on optout +OK get a $4 3000 >2 $10 invalidate *1 $1 a
这个时候若是咱们想排除b
这个key,能够只针对它进行设置:
client caching no +OK get b $1 3
以后对b的变更并不会收到b的失效消息。
注意: OPTIN
和OPTOUT
是针对的非BCAST场景,也就是只有你发送了key的只读命令后,才会跟踪相应的key。而广播模式是不管你是否发送过key的只读命令,只要redis修改了key,都会发送相应key(或者匹配前缀的key)的失效消息。
正常设置时,失效消息是发给全部参与的client,可是若是设置了NOLOOP
,则不会发送给更新这个key的client。
client tracking on bcast noloop +OK set a 1 +OK client tracking off +OK client tracking on bcast +OK set a 1 +OK >2 $10 invalidate *1 $1 a
注意,取消tracking只需调用client tracking off
便可。
最后,让咱们看一下转发消息的处理。这是为了兼容RESP2协议一个处理方式,将失效消息转发给另一个client。
首先咱们查看redis-cli的client id:
127.0.0.1:6379> client list id=4 addr=127.0.0.1:61017 fd=8 name= age=33103 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client user=default
使用telnet链接redis,查看client id:
client id :12
telnet 客户端开启订阅失效消息:
SUBSCRIBE __redis__:invalidate *3 $9 subscribe $20 __redis__:invalidate :1
而后咱们就能够将redis-cli的失效消息转发给telnet client:
client tracking on bcast redirect 12 127.0.0.1:6379> set a 1000 OK
能够看到telnet客户端收到了失效消息:
*3 $7 message $20 __redis__:invalidate *1 $1 a
若是你要转发的目的client开启了RESP3协议,你就不须要RESP3 Pub/Sub了,由于RESP3原生支持Push消息。
redis的tracking feature的实现代码在:tracking.c。