TOC

Redis 客户端缓存

Redis 6 中除了多线程 IO 之外,还有一个改动很难让人不去多留意,那就是客户端缓存。

对于一些热点数据,我们从 Redis 获取之后,常常会在本地线程中也存一份(或者根据语言不同,有些别的第三方组件来专门做这个),也可以有效减小网络消耗。

不过这也算是增加了一级缓存,不可避免的需要涉及数据的同步问题。如果需要比较强的实时性保障,我们就只能放弃采用这个缓存。
可现如今,Redis 能在数据过期数据更新(包括重新设置导致 TTL 变化)之后通知客户端了,这也太贴心了吧。

官方的说法叫做跟踪(Tracking),分两种模式:

  1. 默认模式,Redis 记住客户端读取的 key,有变化的时候通知客户端 key 失效。
  2. 广播模式,客户端订阅一个前缀,这个前缀下有 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 1set 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 也没关系,不需要新的交互协议支持。

参考资料与拓展阅读