Redis系列(十四)、Redis6新特性之RESP3与客户端缓存(Client side caching)
Redis6引入新的RESP3協(xié)議,并以此為基礎(chǔ)加入了客戶端緩存的新特性,在此特性下,大大提高了應(yīng)用程序的響應(yīng)速度,并降低了數(shù)據(jù)庫的壓力,本篇就帶大家來看一下Redis6的新特性:客戶端緩存。
目錄
什么是客戶端緩存
什么是RESP3
客戶端緩存的實(shí)現(xiàn)方式
默認(rèn)模式
原理?
應(yīng)用
廣播模式
原理
應(yīng)用
重定向模式
OPTIN 和 OPTOUT
NOLOOP選項(xiàng)
失效表key上限
Redis6系列文章:
Redis系列(一)、CentOS7下安裝Redis6.0.3穩(wěn)定版
Redis系列(二)、數(shù)據(jù)類型之字符串String?
Redis系列(三)、數(shù)據(jù)類型之哈希Hash
Redis系列(四)、數(shù)據(jù)類型之列表List
Redis系列(五)、數(shù)據(jù)類型之無序集合Set
Redis系列(六)、數(shù)據(jù)類型之有序集合ZSet(sorted_set)
Redis系列(七)、常用key命令
Redis系列(八)、常用服務(wù)器命令?
Redis系列(九)、Redis的“事務(wù)”及Lua腳本操作
Redis系列(十)、詳解Redis持久化方式AOF、RDB以及混合持久化
Redis系列(十一)、Redis6新特性之ACL安全策略(用戶權(quán)限管理)
Redis系列(十二)、Redis6集群搭建及原理(主從、哨兵、集群)
Redis系列(十三)、pub/sub發(fā)布與訂閱(對(duì)比List和Kafka)
Redis系列(十四)、Redis6新特性之RESP3與客戶端緩存(Client side caching)
?
什么是客戶端緩存
?
客戶端緩存是一種用于創(chuàng)建高性能服務(wù)的技術(shù),在此技術(shù)下,應(yīng)用程序端將數(shù)據(jù)庫中的數(shù)據(jù)緩存在應(yīng)用端的內(nèi)存中,當(dāng)應(yīng)用程序訪問數(shù)據(jù)時(shí)直接從本機(jī)內(nèi)存中讀取,而無需連接數(shù)據(jù)庫端,減少了網(wǎng)絡(luò)IO,提升了應(yīng)用程序的響應(yīng)速度,同時(shí)也減少了數(shù)據(jù)庫端的壓力。
官網(wǎng):https://redis.io/topics/client-side-caching
Why RESP3:?http://antirez.com/news/125
沒有客戶端緩存:
應(yīng)用端先查詢Redis端,如果沒有Redis緩存則到原數(shù)據(jù)庫端查詢,如果有則直接從Redis端查詢數(shù)據(jù),更新數(shù)據(jù)時(shí)直接更新MySQL端并同步到Redis內(nèi);
有客戶端緩存:
應(yīng)用端先查詢本地緩存如Guava、Caffeine,若沒有本地緩存則訪問Redis緩存,如果Redis緩存中也沒有則查詢?cè)瓟?shù)據(jù)庫;
客戶端緩存的優(yōu)點(diǎn):
? ? 1.降低了客戶端的數(shù)據(jù)延遲,提升客戶端的響應(yīng)速度;
? ? 2.數(shù)據(jù)庫端接收的查詢減少,降低了數(shù)據(jù)庫端的壓力,因此在相同的數(shù)據(jù)集下可以使用更少的節(jié)點(diǎn)提供服務(wù);
疑問:
為了實(shí)現(xiàn)客戶端緩存,我們面臨這樣的問題,當(dāng)進(jìn)程中緩存了數(shù)據(jù),而數(shù)據(jù)庫端數(shù)據(jù)發(fā)生變更,該如何通知到進(jìn)程,避免客戶端顯示失效的數(shù)據(jù)呢? 在Redis中可以使用上篇介紹過的發(fā)布訂閱機(jī)制,向客戶端發(fā)布數(shù)據(jù)失效的通知,但該模式下即使某些客戶端中沒有包含過期數(shù)據(jù)也會(huì)向所有客戶端發(fā)送無效的消息,非常影響數(shù)據(jù)庫的性能。
在之前的版本中,客戶端緩存采用緩存槽(caching slot)的方式記錄每個(gè)客戶端內(nèi)的key是否發(fā)生變化以及時(shí)同步,最新版中已棄用該方式,而是采用記錄key的名稱或前綴。
什么是RESP3
RESP全程RedisSerializationProtocol,是Redis服務(wù)端與客戶端之間通信的協(xié)議。在Redis6之前的版本,使用的是RESP2協(xié)議,數(shù)據(jù)都是以字符串?dāng)?shù)組的形式返回給客戶端,不管是list還是sorted set。因此客戶端需要自行去根據(jù)類型進(jìn)行解析,這樣會(huì)增加了客戶端實(shí)現(xiàn)的復(fù)雜性。
為了照顧老用戶,Redis6在兼容 RESP2 的基礎(chǔ)上,開始支持 RESP3,但未來會(huì)全面切換到RESP3之上。今天的客戶端緩存在基于RESP3才能有更好的實(shí)現(xiàn),可以在同一個(gè)連接中運(yùn)行數(shù)據(jù)的查詢和接收失效消息。而目前在RESP2上實(shí)現(xiàn)的客戶端緩存,需要兩個(gè)客戶端連接以轉(zhuǎn)發(fā)重定向的形式實(shí)現(xiàn)。
在Redis6中我們可以使用HELLO命令在RESP2和RESP3協(xié)議之間進(jìn)行切換:
#使用RESP2協(xié)議
HELLO 2
#使用RESP3協(xié)議
HELLO 3
客戶端緩存的實(shí)現(xiàn)方式
Redis客戶端緩存被稱為Tracking,在RESP3協(xié)議下,有兩種模式:
默認(rèn)模式:服務(wù)器記錄客戶端訪問了哪些key,當(dāng)其中的key發(fā)生變更時(shí)給客戶端發(fā)送失效信息,消耗服務(wù)器端內(nèi)存;
廣播模式:客戶端訂閱訪問過的key的前綴,當(dāng)符合模式的key發(fā)生變更就會(huì)被通知(即使變更的key沒有被客戶端緩存),服務(wù)器端不記錄客戶端訪問的key,因此不會(huì)消耗服務(wù)器端的內(nèi)存;
默認(rèn)模式
原理?
服務(wù)器端會(huì)記錄訪問key的客戶端列表并維護(hù)一個(gè)表,這個(gè)表被稱為失效表(Invalidation Table),如果插入一個(gè)新的key,服務(wù)器端會(huì)給客戶端發(fā)送失效信息并從客戶端剔除該key,避免提供過時(shí)數(shù)據(jù)。
在失效表中不會(huì)記錄key和客戶端內(nèi)對(duì)應(yīng)指針的映射關(guān)系,只會(huì)記錄key的指針和各客戶端ID(每個(gè)Redis客戶端都有一個(gè)唯一ID)的映射關(guān)系,當(dāng)發(fā)送完失效信息后,客戶端剔除key,服務(wù)端從失效表中刪除key的指針和客戶端ID的映射關(guān)系。
在失效表中key的命名空間只有一個(gè),即是說,在db0~db15中相同的key名,在失效表中會(huì)記錄在同一個(gè)命名空間內(nèi),即使客戶端緩存的是db0內(nèi)的key,如果db1內(nèi)的同名key被更新,也會(huì)通知客戶端剔除db0內(nèi)的同名key。
客戶端緩存的操作就是對(duì)key的內(nèi)存地址進(jìn)行操作:?
1.當(dāng)開啟客戶端緩存的客戶端從Redis獲取數(shù)據(jù)時(shí),Redis服務(wù)端會(huì)調(diào)用enableTracking方法在上面的失效表中記錄key和客戶端ID的映射關(guān)系;
2.若key被修改,則Redis服務(wù)端會(huì)調(diào)用trackingInvalidateKey函數(shù)根據(jù)該key被緩存的客戶端列表ID調(diào)用sendTrackingMessage函數(shù)向它們發(fā)送失效消息。(發(fā)送失效消息前會(huì)檢查客戶端的Client_Tracking和NOLOOP狀態(tài))
3.服務(wù)端發(fā)送完失效消息后會(huì)從失效表中將該key與客戶端ID的映射關(guān)系刪除;
4.由于客戶端可能會(huì)在開啟之后關(guān)閉了緩存功能,在失效表中刪除key和該客戶端ID之間的映射關(guān)系比較消耗性能,因此服務(wù)端采用懶刪除的方式,只是將該客戶端的Client_Tracking相關(guān)標(biāo)志位刪除;
應(yīng)用
上面提到我們可以使用HELLO命令切換RESP3協(xié)議,在此協(xié)議下我們使用tracking命令開啟track追蹤,此時(shí)服務(wù)端會(huì)記錄客戶端在連接的生命周期內(nèi)的只讀的key,當(dāng)客戶端開啟track追蹤后,key的數(shù)據(jù)會(huì)被緩存在客戶端內(nèi)存中:
#開啟RESP3協(xié)議
HELLO 3
#開啟tracking客戶端緩存
client tracking on
#關(guān)閉tracking客戶端緩存
client tracking off
為了演示失效消息的通知,這里使用telnet測(cè)試客戶端緩存,然后在另一個(gè)redis-cli對(duì)key做操作:
# 使用telnet連接客戶端 telnet wykd 6379#auth命令登錄服務(wù)器(如果沒有密碼可以忽略) auth default wyk123456#開啟RESP3 hello 3#開啟客戶端緩存tracking client tracking on#查詢一個(gè)key 同時(shí)該key會(huì)被緩存 get name#在另一個(gè)redis客戶端中 修改/刪除/過期/淘汰 該key set name new_values#在telnet窗口會(huì)受到key失效的消息如下: get nam #客戶端緩存key$3 wyk>2 # 失效消息 $10 invalidate *1 $4 name#關(guān)閉客戶端緩存tracking,關(guān)閉后不會(huì)再收到key的失效消息 client tracking off當(dāng)開啟了tracking后,客戶端緩存的key如果在別處被修改為與原值一樣,也會(huì)收到失效消息;
當(dāng)客戶端緩存失效后,該key再被修改時(shí),客戶端不會(huì)再收到消息,也就是再查詢?cè)搆ey之后才會(huì)在客戶端緩存key的值;
當(dāng)客戶端緩存的key因過期策略或內(nèi)存淘汰策略被驅(qū)逐時(shí),服務(wù)端也會(huì)發(fā)送失效消息給開啟了tracking的客戶端:
當(dāng)開啟了tracking的客戶端獲取的key不存在時(shí),如果在另一個(gè)客戶端新增/修改了該key,那個(gè)tracking的客戶端也會(huì)收到失效消息,可見如果key不存在也會(huì)在客戶端緩存中緩存空值,這種結(jié)果因人而異,個(gè)人認(rèn)為這樣不太好,一是客戶端會(huì)徒增大量的無用緩存,而是服務(wù)端的失效表會(huì)維護(hù)更多的key->clientID的映射關(guān)系。
廣播模式
原理
另一個(gè)客戶端緩存的實(shí)現(xiàn)方式是廣播模式(broadcasting),廣播不會(huì)消耗服務(wù)端的內(nèi)存,而是向各客戶端發(fā)送更多的失效消息。廣播模式與默認(rèn)模式類似,不同的是廣播模式下維護(hù)的是前綴表,在前綴表中存儲(chǔ)客戶端訂閱的key前綴與客戶端ID之間的映射關(guān)系。
在這種模式下,有以下的主要行為:
?
1.客戶端使用BCAST選項(xiàng)開啟客戶端緩存的廣播模式,并使用PREFIX指定一個(gè)或多個(gè)前綴。如果不指定前綴則默認(rèn)客戶端接收所有的key的失效消息,如果指定則只會(huì)接收匹配該前綴的key的失效消息;
2.在廣播模式下,服務(wù)端維護(hù)的不是失效表,而是前綴表(Prefix Table),每個(gè)前綴映射一些客戶端ID;
3.每次修改跟任意前綴匹配的鍵時(shí),所有訂閱該前綴的客戶端都將收到失效消息;
4.服務(wù)端的CPU消耗與訂閱的key前綴數(shù)量成正比,訂閱的key前綴數(shù)量越多服務(wù)器端壓力越大;
5.服務(wù)器可以為訂閱特定前綴的客戶端創(chuàng)建單個(gè)回復(fù),并向所有的客戶端發(fā)送相同的回復(fù)來進(jìn)行優(yōu)化,有助于降低CPU使用率。
應(yīng)用
同樣,在廣播模式下也需要開啟RESP3協(xié)議,這里我們?nèi)匀皇褂脛偛诺膖elnet會(huì)話進(jìn)行演示。
使用下面的命令開啟廣播模式的客戶端緩存,上面提到廣播模式下服務(wù)端維護(hù)一個(gè)前綴表,記錄key的前綴和客戶端id的映射關(guān)系,因此我們也可以在客戶端指定需要接收失效消息的key前綴:
#telnet訪問redis客戶端(略)
#開啟RESP3
hello 3
#開啟廣播模式的客戶端緩存tracking,默認(rèn)會(huì)收到所有的key的失效信息
client tracking on bcast
#開啟廣播模式的客戶端緩存tracking,只接受指定前綴'wyk'的key的失效信息
client tracking on bcast prefix wyk
廣播模式下,只要符合客戶端設(shè)置的key前綴的key發(fā)生新增、修改、刪除、過期、淘汰等動(dòng)作,即使該key沒有被該客戶端緩存,也會(huì)收到key的失效消息;
重定向模式
為了兼容RESP2協(xié)議,在Redis6中客戶端緩存可以以重定向(Redirect)的方式實(shí)現(xiàn),不再使用RESP3原生支持的PUSH消息,而是將消息通過Pub/Sub通知給另外一個(gè)客戶端連接:
#查看客戶端id
client id
#用于接收失效消息的客戶端訂閱頻道
subscribe _redis_:invalidate
#客戶端開啟Tracking客戶端緩存 并指定需要接收失效消息的客戶端ID
client tracking on bcast redirect receive_client_id
OPTIN和OPTOUT
在默認(rèn)模式或重定向模式下,我們可以有選擇的對(duì)需要的key進(jìn)行緩存,而由于廣播模式是匹配key前綴,因此不能使用此命令。
#RESP3 默認(rèn)模式
#切換RESP3協(xié)議
hello 3
#開啟客戶端緩存optin選項(xiàng)
client tracking on optin
#此命令后面第一個(gè)只讀key會(huì)被緩存
client caching yes
#RESP2 重定向模式
hello 2
#開啟客戶端緩存optin選項(xiàng),1234是接收失效消息的客戶端id
client tracking on REDIRECT 1234 OPTIN
#此命令后面第一個(gè)只讀key會(huì)被緩存
client caching yes
OPTIN:只有執(zhí)行client caching yes之后的第一個(gè)key才會(huì)被緩存;
OPTOUT:與OPTIN相反,執(zhí)行client caching on之后的第一個(gè)只讀key不會(huì)被緩存;
注意:在redis6.0.3版本中optin和optout選項(xiàng)時(shí)靈時(shí)不靈,可能還有BUG;
NOLOOP選項(xiàng)
我們的客戶端修改自己已緩存的key的時(shí)候也會(huì)收到這個(gè)key的過期信息,事實(shí)上這個(gè)客戶端是不需要收到該消息的,這造成了浪費(fèi),因此我們可以使用NOLOOP選項(xiàng)將該客戶端設(shè)置為:本客戶端修改的key不會(huì)收到相關(guān)的失效信息。
#開啟客戶端緩存的NOLOOP選項(xiàng)
client tracking on noloop
開啟noloop選項(xiàng)的客戶端,如果在該客戶端上修改它已經(jīng)緩存的key,自己不會(huì)收到該key的失效消息:
沒開啟noloop選項(xiàng)的客戶端,如果在該客戶端上修改它已經(jīng)緩存的key,自己也會(huì)收到該key的失效消息:
失效表key上限
可以使用?tracking_table_max_keys參數(shù)修改服務(wù)端失效表內(nèi)記錄的緩存的key的數(shù)量,當(dāng)失效表內(nèi)記錄的緩存key達(dá)到配置的數(shù)量時(shí)會(huì)隨機(jī)從失效表內(nèi)移除緩存:
#查詢最大緩存的數(shù)量
config get tracking-table-max-keys
#設(shè)置最大緩存數(shù)量為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客戶端緩存設(shè)計(jì)(In-Process caching)
帶你100% 地了解 Redis 6.0 的客戶端緩存
?
希望本文對(duì)你有幫助,請(qǐng)點(diǎn)個(gè)贊鼓勵(lì)一下作者吧~ 謝謝!
總結(jié)
以上是生活随笔為你收集整理的Redis系列(十四)、Redis6新特性之RESP3与客户端缓存(Client side caching)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高并发之--Guava Cache
- 下一篇: linux cmake编译源码,linu