Redis系列(十四)、Redis6新特性之RESP3與客戶端緩存(Client side caching)

Redis6引入新的RESP3協議,並以此爲基礎加入了客戶端緩存的新特性,在此特性下,大大提高了應用程序的響應速度,並降低了數據庫的壓力,本篇就帶大家來看一下Redis6的新特性:客戶端緩存。


目錄

什麼是客戶端緩存

什麼是RESP3

客戶端緩存的實現方式

默認模式

原理 

應用

廣播模式

原理

應用

重定向模式

OPTIN 和 OPTOUT

NOLOOP選項

失效表key上限


Redis6系列文章

Redis系列(一)、CentOS7下安裝Redis6.0.3穩定版

Redis系列(二)、數據類型之字符串String 

Redis系列(三)、數據類型之哈希Hash

Redis系列(四)、數據類型之列表List

Redis系列(五)、數據類型之無序集合Set

Redis系列(六)、數據類型之有序集合ZSet(sorted_set)

Redis系列(七)、常用key命令

Redis系列(八)、常用服務器命令 

Redis系列(九)、Redis的“事務”及Lua腳本操作

Redis系列(十)、詳解Redis持久化方式AOF、RDB以及混合持久化

Redis系列(十一)、Redis6新特性之ACL安全策略(用戶權限管理)

Redis系列(十二)、Redis6集羣搭建及原理(主從、哨兵、集羣)

Redis系列(十三)、pub/sub發佈與訂閱(對比List和Kafka)

Redis系列(十四)、Redis6新特性之RESP3與客戶端緩存(Client side caching)


什麼是客戶端緩存

客戶端緩存是一種用於創建高性能服務的技術,在此技術下,應用程序端將數據庫中的數據緩存在應用端的內存中,當應用程序訪問數據時直接從本機內存中讀取,而無需連接數據庫端,減少了網絡IO,提升了應用程序的響應速度,同時也減少了數據庫端的壓力。

官網:https://redis.io/topics/client-side-caching

Why RESP3:http://antirez.com/news/125

沒有客戶端緩存: 

應用端先查詢Redis端,如果沒有Redis緩存則到源數據庫端查詢,如果有則直接從Redis端查詢數據,更新數據時直接更新MySQL端並同步至Redis內;

有客戶端緩存: 

應用端先查詢本地緩存如Guava、Caffeine,若沒有本地緩存則訪問Redis緩存,如果Redis緩存中也沒有則查詢源數據庫;

客戶端緩存的優點

  1. 降低了客戶端的數據延遲,提升客戶端的響應速度;
  2. 數據庫端接收的查詢減少,降低了數據庫端的壓力,因此在相同的數據集下可以使用更少的節點提供服務;

疑問

爲了實現客戶端緩存,我們面臨這樣的問題,當進程中緩存了數據,而數據庫端數據發生變更,該如何通知到進程,避免客戶端顯示失效的數據呢? 在Redis中可以使用上篇介紹過的發佈訂閱機制,向客戶端發佈數據失效的通知,但該模式下即使某些客戶端中沒有包含過期數據也會向所有客戶端發送無效的消息,非常影響數據庫的性能。

在之前的版本中,客戶端緩存採用緩存槽(caching slot)的方式記錄每個客戶端內的key是否發生變化以及時同步,最新版中已棄用該方式,而是採用記錄key的名稱或前綴。 

什麼是RESP3

RESP 全稱 REdisSerializationProtocol,是 Redis 服務端與客戶端之間通信的協議。在Reds6之前的版本,使用的是RESP2協議,數據都是以字符串數組的形式返回給客戶端,不管是 list 還是 sorted set。因此客戶端需要自行去根據類型進行解析,這樣會增加了客戶端實現的複雜性。

爲了照顧老用戶,Redis6在兼容 RESP2 的基礎上,開始支持 RESP3,但未來會全面切換到RESP3之上。今天的客戶端緩存在基於RESP3纔能有更好的實現,可以在同一個連接中運行數據的查詢和接收失效消息。而目前在RESP2上實現的客戶端緩存,需要兩個客戶端連接以轉發重定向的形式實現,。

在Redis6中我們可以使用HELLO命令在RESP2和RESP3協議之間進行切換:

#使用RESP2協議
HELLO 2
#使用RESP3協議
HELLO 3

客戶端緩存的實現方式

Redis客戶端緩存被稱爲Tracking,在RESP3協議下,有兩種模式:

默認模式:服務器記錄客戶端訪問了哪些key,當其中的key發生變更時給客戶端發送失效信息,消耗服務器端內存;

廣播模式:客戶端訂閱訪問過的key的前綴,當符合模式的key發生變更就會被通知(即使變更的key沒有被客戶端緩存),服務器端不記錄客戶端訪問的key,因此不會消耗服務器端的內存;

默認模式

原理 

服務器端會記錄訪問key的客戶端列表並維護一個表,這個表被稱爲失效表(Invalidation Table),如果插入一個新的key,服務器端會給客戶端發送失效信息並從客戶端踢除該key,避免提供過時數據。

在失效表中不會記錄key和客戶端內對應指針的映射關係,只會記錄key的指針和各客戶端ID(每個Redis客戶端都有一個唯一ID)的映射關係,當發送完失效信息後,客戶端剔除key,服務端從失效表中刪除key的指針和客戶端ID的映射關係。

在失效表中key的命名空間只有一個,即是說,在db0~db15中相同的key名,在失效表中會記錄在同一個命名空間內,即使客戶端緩存的是db0內的key,如果db1內的同名key被更新,也會通知客戶端剔除db0內的同名key。

客戶端緩存的操作就是對key的內存地址進行操作: 

  1. 當開啓客戶端緩存的客戶端從Redis獲取數據時,Redis服務端會調用 enableTracking 方法在上面的失效表中記錄key和客戶端ID的映射關係;
  2. 若key被修改,則Redis服務端會調用 trackingInvalidateKey 函數根據該key被緩存的客戶端列表ID調用 sendTrackingMessage 函數向它們發送失效消息。(發送失效消息前會檢查客戶端的Client_Tracking和NOLOOP狀態)
  3. 服務端發送完失效消息後會從失效表中將該key與客戶端ID的映射關係刪除;
  4. 由於客戶端可能會在開啓之後關閉了緩存功能,在失效表中刪除key和該客戶端ID之間的映射關係比較消耗性能,因此服務端採用懶刪除的方式,只是將該客戶端的Client_Tracking相關標誌位刪除;

應用

上面提到我們可以使用HELLO命令切換RESP3協議,在此協議下我們使用tracking命令開啓track追蹤,此時服務端會記錄客戶端在連接的生命週期內的只讀的key,當客戶端開啓track追蹤後,key的數據會被緩存在客戶端內存中:

#開啓RESP3協議
HELLO 3

#開啓tracking 客戶端緩存
client tracking on

#關閉tracking 客戶端緩存
client tracking off

爲了演示失效消息的通知,這裏使用telnet測試客戶端緩存,然後在另一個redis-cli對key做操作:

#使用telnet連接客戶端
telnet wykd 6379

#auth命令登錄服務器(如果沒有密碼可以忽略)
auth default wyk123456

#開啓RESP3
hello 3

#開啓客戶端緩存 tracking
client tracking on

#查詢一個key 同時該key會被緩存
get name

#在另一個redis客戶端中 修改/刪除/過期/淘汰 該key
set name new_values

#在telnet窗口會收到key失效的消息如下:
get name   #客戶端緩存key
$3
wyk

>2         #失效消息
$10
invalidate
*1
$4
name

#關閉客戶端緩存 tracking,關閉後不會再收到key的失效消息
client tracking off

當開啓了tracking後,客戶端緩存的key如果在別處被修改爲與原值一樣,也會收到失效消息;

當客戶端緩存失效後,該key再被修改時,客戶端不會再收到消息,也就是再查詢該key之後 纔會在客戶端緩存key的值;

當客戶端緩存的key因過期策略內存淘汰策略被驅逐時,服務端也會發送失效消息給開啓了tracking的客戶端:

當開啓了tracking的客戶端獲取的key不存在時,如果在另一個客戶端新增/修改了該key,那個tracking的客戶端也會收到失效消息,可見如果key不存在也會在客戶端緩存中緩存空值,這種結果因人而異,個人認爲這樣不太好,一是客戶端會徒增大量的無用緩存,二是服務端的失效表會維護更多的key->clientID的映射關係。

廣播模式

原理

另一個客戶端緩存的實現方式是廣播模式(broadcasting),廣播不會消耗服務端的內存,而是向各客戶端發送更多的失效消息。廣播模式與默認模式類似,不同的是廣播模式下維護的是前綴表,在前綴表中存儲客戶端訂閱的key前綴與客戶端ID之間的映射關係。

在這種模式下,有以下的主要行爲:

  1. 客戶端使用 BCAST 選項開啓客戶端緩存的廣播模式,並使用 PREFIX 指定一個或多個前綴。如果不指定前綴則默認客戶端接收所有的key的失效消息,如果指定則只會接收匹配該前綴的key的失效消息;
  2. 在廣播模式下,服務端維護的不是失效表,而是前綴表(Prefix Table),每個前綴映射一些客戶端ID;
  3. 每次修改跟任意前綴匹配的鍵時,所有訂閱該前綴的客戶端都將收到失效消息;
  4. 服務端的CPU消耗與訂閱的key前綴數量成正比,訂閱的key前綴數量越多服務器端壓力越大;
  5. 服務器可以爲訂閱特定前綴的客戶端創建單個回覆,並向所有的客戶端發送相同的回覆來進行優化,有助於降低CPU使用率。

應用

同樣,在廣播模式下也需要開啓RESP3協議,這裏我們仍然使用剛纔的telnet會話進行演示。

使用下面的命令開啓廣播模式的客戶端緩存,上面提到廣播模式下服務端維護一個前綴表,記錄key的前綴和客戶端id的映射關係,因此我們也可以在客戶端指定需要接收失效消息的key前綴:

#telnet訪問redis客戶端(略)
#開啓RESP3
hello 3

#開啓廣播模式的客戶端緩存tracking,默認會收到所有的key的失效信息
client tracking on bcast

#開啓廣播模式的客戶端緩存tracking,只接受指定前綴'wyk'的key的失效信息
client tracking on bcast prefix wyk

廣播模式下,只要符合客戶端設置的key前綴的key發生新增、修改、刪除、過期、淘汰等動作,即使該key沒有被該客戶端緩存,也會收到key的失效消息;

重定向模式

爲了兼容RESP2協議,在Redis6中客戶端緩存可以以重定向(Redirect)的方式實現,不再使用 RESP3 原生支持的PUSH消息,而是將消息通過 Pub/Sub 通知給另外一個客戶端連接:

#查看客戶端id
client id

#用於接收失效消息的客戶端訂閱頻道
subscribe _redis_:invalidate

#客戶端開啓Tracking客戶端緩存 並指定需要接收失效消息的客戶端ID
client tracking on bcast redirect receive_client_id

OPTIN 和 OPTOUT

在默認模式或重定向模式下,我們可以有選擇的對需要的key進行緩存,而由於廣播模式是匹配key前綴,因此不能使用此命令。

#RESP3 默認模式
#切換RESP3協議
hello 3
#開啓客戶端緩存optin選項
client tracking on optin
#此命令後面第一個只讀key會被緩存
client caching yes


#RESP2 重定向模式
hello 2
#開啓客戶端緩存optin選項,1234是接收失效消息的客戶端id
client tracking on REDIRECT 1234 OPTIN  
#此命令後面第一個只讀key會被緩存
client caching yes

OPTIN : 只有執行client caching yes之後的第一個key纔會被緩存;

OPTOUT : 與OPTIN相反,執行client caching no之後的第一個只讀key不會被緩存;

注意:在redis6.0.3版本中outin和optout選項時靈時不靈,可能還有BUG;

NOLOOP選項

我們的客戶端修改自己已緩存的key的時候也會收到這個key的過期信息,事實上這個客戶端是不需要收到該消息的,這造成了浪費,因此我們可以使用NOLOOP選項將該客戶端設置爲:本客戶端修改的key不會收到相關的失效信息。

#開啓客戶端緩存的NOLOOP選項
client tracking on noloop

開啓noloop選項的客戶端,如果在該客戶端上修改它已經緩存的key,自己不會收到該key的失效消息:

沒開啓noloop選項的客戶端,如果在該客戶端上修改它已經緩存的key,自己也會收到該key的失效消息:

失效表key上限

可以使用 tracking_table_max_keys參數修改服務端失效表內記錄的緩存的key的數量,當失效表內記錄的緩存key達到配置的數量時會隨機從失效表內移除緩存:

#查詢最大緩存的數量
config get tracking-table-max-keys

#設置最大緩存數量爲300
config set tracking-table-max-keys 300

 

參考文章:

Redis server-assisted client side caching 

Why RESP3 will be the only protocol supported by Redis 6

Redis客戶端緩存設計(In-Process caching)

帶你100% 地瞭解 Redis 6.0 的客戶端緩存

 

希望本文對你有幫助,請點個贊鼓勵一下作者吧~ 謝謝!

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