Redis 6 中除了多线程 IO 之外,还有一个改动很难让人不去多留意,那就是客户端缓存。
全名:server-assisted client-side caching,也就是服务端辅助客户端缓存。
对于一些热点数据,我们从 Redis 获取之后,常常会在本地线程中也存一份(或者根据语言不同,有些别的第三方组件来专门做这个),也可以有效减小网络消耗。
不过这也算是增加了一级缓存,不可避免的需要涉及数据的同步问题。如果需要比较强的实时性保障,我们就只能放弃采用这个缓存。
可现如今,Redis 能在数据过期
或数据更新
(包括重新设置导致 TTL 变化)之后通知客户端了,这也太贴心了吧。
官方的说法叫做跟踪(Tracking),分两种模式:
- 默认模式,Redis 记住客户端读取的 key,有变化的时候通知客户端 key 失效。
- 广播模式,客户端订阅一个前缀,这个前缀下有 key 变更时,Redis 推送一个消息过来。
与之配套的是新的 Redis 协议:RESP3,之前是 RESP2。
# 新增命令:切换协议
hello [protover [AUTH username password] [SETNAME clientname]]
# 开启服务器跟踪
client tracking on|off [REDIRECT client-id] [PREFIX prefix [PREFIX prefix ...]] [BCAST] [OPTIN] [OPTOUT] [NOLOOP]
# 开启客户端缓存
client caching yes|no
简单的 tracking on
就是开启普通模式,客户端读取过的 key 变动之后都会发送消息过来。可以通过以下参数定制服务器行为:
- REDIRECT, 转发给另一个客户端
- BCAST, 广播模式,可以指定多个 prefix,如果不指定就认为所有 key 变更都需要通知
- OPTIN
- OPTOUT
- NOLOOP,不向当前客户端推送它自己的操作(不是默认行为!!)
实验
docker pull redis
docker run -itd --name redis-test -p 19888:6379 redis
docker ps
如果直接采用 redis-cli -p 19888
去连,是不能切到 RESP3 的,版本不支持,报错:Error: Protocol error, got "%" as reply type byte
可以采用 docker 中的 client-cli 尝尝鲜:
docker exec -it redis-test /bin/bash
hello 3
1# "server" => "redis"
2# "version" => "6.0.10"
3# "proto" => (integer) 3
4# "id" => (integer) 8
5# "mode" => "standalone"
6# "role" => "master"
7# "modules" => (empty array)
不过好像观察不到推送的消息,可能 redis-cli 会过滤这个消息。
这个客户端我们称之为 redis-cli。
另外再启动两个 telnet localhost 19888
,分别称之为 telnet-a,telnet-b。
普通模式
telnet-a:
hello 3
client tracking on
set x 1
get x
如果在 redis-cli 中 set x 2
,telnet-a 会收到:
>2
$10
invalidate
*1
$1
x
注意:hello 3
很重要,后面执行都没关系,只有在切到 RESP3 之后才能收到失效消息。
注意:在重新 get 之前,不会再收到 x 的失效消息。
广播模式
telnet-a:
注意:直接重开 Tracking 会报错,需要先 off 一下。
client tracking on prefix token bcast
# -ERR You can't switch BCAST mode on/off before disabling tracking for this client, and then re-enabling it with a different mode.
client tracking off
client tracking on prefix token bcast
set x 1
set token:a 1
get x
get token:a
redis-cli 中 set x 1
和 set token:a 1
看看。
optin
telnet-a:
client tracking off
client tracking on optin
client caching yes
get x
只有紧跟 client cacing yes
的那一次读操作才会 Tracking
相当于仅包含
optout
telnet-a:
client tracking off
client tracking on optout
client caching no
get x
只有紧跟 client cacing no
的那一次读操作才不会 Tracking
相当于排除
转发
在 telnet-a 中使用 client id
查看客户端编号(我看到的是 18)。
telnet-b:
client tracking on redirect 18
get x
然后在 redis-cli 中 set x 1
试试,会。
注意:这里没有 hello 3
也没关系,不需要新的交互协议支持。