大哥,Redis 6.0 除了多線程,別忘了這個牛逼特性

Redis 6.0的新特性也是在一步步的討論和優化中確定的。

很多的特性已經在之前的RC等版本中介紹過了。

但是正式GA版中也在一些新的變化:

  • SSL

  • ACL: 更好,命令支持

  • RESP3

  • Client side caching:重新設計

  • Threaded I/O

  • Diskless replication on replicas

  • Cluster support in Redis-benchmark and improved redis-cli cluster support

  • Disque in beta as a module of Redis: 開始侵入消息隊列領域

  • Redis Cluster Proxy

  • 支持RDB不再使用時可立即刪除,針對不落盤的場景

  • PSYNC2: 優化的複製協議

  • 超時設置支持更友好

  • 更快的RDB加載,20% ~ 30%的提升

  • STRALGO,新的字符串命令,目前只有一個實現LCS (longest common subsequence)

@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.

本文主要關注Client side caching(客戶端緩存)這一特性。

smallnest/RESP3 是Redis RESP3協議的解析庫,你可以使用它和Redis底層通訊,或者包裝它實現新版的Redis client庫或者Redis Server端。

一年前,當 @antirez 參加完紐約Redis大會後,5:30就在旅店中醒來了,面對曼哈頓街頭的美麗景色,在芸芸衆生中思索Redis的未來。包括客戶端緩存。

其實,客戶端緩存特性是收到Redis Conf 2018的Ben Malec的影響,一下子打開了 @antirez 思路。 我們知道, 很多公司使用Redis做緩存系統,並且很好的提高了數據訪問的性能,但是很多企業爲了進一步應對熱點數據,還是會在redis的client端緩存一部分熱點數據,用來應對喫瓜事件。比如在微博我們經常遇到的是明星出軌、明星分分合合、突發事件等等,每年都會有幾次突發的事件,微博除了使用Redis做緩存避免直接訪問數據庫,還會在前面加更多的cache層,比如L1 cache等,採用memcached等產品作爲熱數據的緩存。那麼就有一個問題,如何能夠及時的同步這些cache和redis的數據呢?Ben提供了非常有意思的想法。

佇立在曼哈頓的街頭,@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會主動發送一條失效消息

  • REDIRECT : 將失效消息轉發給另外一個客戶端。當我們不使用RESP3而是使用老的RESP2和Redis通訊時,client本身不支持處理失效消息,所以可以開啓一個支持Pub/Sub客戶端處理失效消息。當然如果客戶端支持RESP3也可以將失效消息轉發給另外一個客戶端。這個cace我們放在最後演示。

  • BCAST: 使用廣播模式開始tracking。在這種模式下客戶端需要設置將track的key的前綴,這些key的失效消息會廣播給所有參與的客戶端,不管這些客戶端是否請求/緩存額這些key。不開始廣播模式時,Redis只會track那些只讀命令請求的key,並且只會報告一次失效消息。

  • PREFIX : 只應用了廣播模式,註冊一個key的前綴。所有以這個前綴開始的key有修改時,都會發送失效消息。可以註冊多個前綴。如果不設置前綴,那麼廣播模式會track每一個key。

  • OPTIN: 當廣播模式沒有激活時,正常不會track只讀命令的key,除非它們在CLIENT CACHING yes之後被調用。

  • OPTOUT: 當廣播模式沒有激活時,正常會track只讀命令的key,除非它們在CLIENT CACHING off之後被調用。

  • NOLOOP: 不發送client自己修改的key。

下面讓我們一一介紹每個選項。

測試環境搭建

首先讓我們介紹RESP3協議相關的選項,REDIRECT <id>放在最後介紹。

在嘗試之前,你首先需要安裝一個redis 6.x的版本,目前時6.0.1。在官方網站上有源代碼的下載,編譯安裝也很簡單:

make distcleanmakemake test
sudo make install

相信很快就有編譯好的二進制包可以下載。

啓動server, 它會在6379端口啓動一個服務:

redis-server

使用redis-cli訪問,默認訪問本機的6379實例:

redis-cli

當然你可以通過-h查看額外的參數配置,比如使用其它端口等等,這裏我們使用最簡單的例子,重點是瞭解客戶端緩存的特性。

有時候爲了更好的觀察redis的返回結果,我們使用telnet而不是redis-cli作爲client連接redis,因爲redis-cli對結果做了處理,尤其是失效消息,你可能無法觀測到。

BCAST 廣播模式 (client tracking on)

啓動redis server:

8d07cbddb2754c71a653a3aebf228461

 

啓動redis-cli:

4a502306919f42859507e471f074a54c

 

當然,我們使用telnet來測試,方便觀察redis的返回結果,剛纔redis-cli用來更新key值,輔助測試。 連接上之後發送hello 3開啓RESP3協議:

➜  ~ telnet localhost 6379
Trying ::1...
Connected to localhost.
Escape character is '^]'.
hello 3%7$6server$5redis$7version$56.0.1
......

之後嘗試開啓tracking並讀取a的值:

client tracking on
+OKset a 1
+OKget a$11

這個時候如果使用redis-cli作爲另外一個client更新a的值,telnet這個client應該能獲得通知:

127.0.0.1:6379> set a 2OK

觀察telnet,它收到了一個失效消息:

>2$10invalidate
*1$1a

注意它採用RESP3中的PUSH類型(>)。

如果這個使用你再使用redis-cli更新a的值,telnet不會再收到失效消息。 除非telnet client再get a一次,重新tracking a的值。

可以隨時取消tracking:

client tracking off

tracking特定前綴的key (client tracking on)

上面的方式會tracking所有的key,如果你只想跟蹤特定的key, 目前redis提供了一種方式,也就是前綴匹配的方式。你可以只tracking特定前綴的key。 它只應用了廣播模式。

使用telnet client設定前綴和開啓tracking:

hello 3.......client tracking on prefix a bcast
+OKclient 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 100OK127.0.0.1:6379> set user:32432723213 goodOK127.0.0.1:6379> set feed:6532343243432 abcOK

telnet client收到abc和user:32432723213的失效消息,而不會收到feed:6532343243432的失效消息:

>2$10invalidate
*1$3abc>2$10invalidate
*1$16user: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
+OKget a$12

接下來我們發送client caching yes,緊接着獲取a的值,這個時候如果再修改a的值,你就可以收到一條a的失效消息:

client caching yes+OK
get a$41000>2$10invalidate*1$1a

必須是緊跟着client caching yes嗎?是的,比如發送下面的命令,只會tracking b,而不是a:

client caching yes+OKget b
_get a$42000

選擇退出

如果使用OPTOUT,你也可以有選擇的退出tracking。 只有你發送client caching off之後的下一條的只讀命令的key纔會停止tracking, 否則其它的只讀命令中的key都會被tracking。

可以看到它和OPTIN正好相反,你可以根據你的場景來選擇。

比如下面的例子,開啓OPTOUT之後,對任意的key的變動都收到失效消息:

client tracking on optout
+OKget a$43000
>2$10invalidate*1$1a

這個時候如果我們想排除b這個key,可以只針對它進行設置:

client caching no+OKget b$13

之後對b的變動並不會收到b的失效消息。

注意: OPTIN和OPTOUT是針對的非BCAST場景,也就是隻有你發送了key的只讀命令後,纔會跟蹤相應的key。而廣播模式是無論你是否發送過key的只讀命令,只要redis修改了key,都會發送相應key(或者匹配前綴的key)的失效消息。

NOLOOP

正常設置時,失效消息是發給所有參與的client,但是如果設置了NOLOOP,則不會發送給更新這個key的client。

client tracking on bcast noloop
+OKset a 1
+OKclient tracking off
+OKclient tracking on bcast
+OKset a 1
+OK
>2$10invalidate*1$1a

注意,取消tracking只需調用client tracking off即可。

REDIRECT

最後,讓我們看一下轉發消息的處理。這是爲了兼容RESP2協議一個處理方式,將失效消息轉發給另外一個client。

首先我們查看redis-cli的client id:

127.0.0.1:6379> client listid=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$9subscribe$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$7message$20__redis__:invalidate*1$1a

如果你要轉發的目的client開啓了RESP3協議,你就不需要RESP3 Pub/Sub了,因爲RESP3原生支持Push消息。

redis的tracking feature的實現代碼在:tracking.c。

推薦學習這個牛逼的Redis教程:阿里P8架構師用450分鐘時間讓你精通Redis,面試再也不怕被問Redis!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章