Redis 6.0 新特性篇:Client Side Cache 是嘛玩意?
開(kāi)篇寄語(yǔ)
不要吝嗇你的贊美,如果別人做的很好,就給他正反饋,這也是一種利他。
另外,少關(guān)注用「贊美」投票的事物,而多關(guān)注用「交易」投票的事物。
判斷一個(gè)人是否牛逼,不是看網(wǎng)上有多少人贊美他,而是看有多少人愿意跟他發(fā)生交易、贊賞、支付、下單。
因?yàn)橘澝捞畠r(jià),而愿意與他發(fā)生交易,才是真正的信任。
為啥需要客戶端緩存
Redis 的Tracking Feature 的實(shí)現(xiàn)代碼在: https://github.com/antirez/redis/blob/unstable/src/tracking.c。
很多公司使用 Redis 做緩存系統(tǒng),并且很好的提高了數(shù)據(jù)訪問(wèn)的性能,為了進(jìn)一步應(yīng)對(duì)熱點(diǎn)數(shù)據(jù),還是會(huì)在 Redis 的 Client 端緩存一部分熱點(diǎn)數(shù)據(jù),用來(lái)應(yīng)對(duì)「吃瓜事件」。
比如,「這該死的 996 福報(bào)」、「吳亦凡之大方牢房」、「時(shí)間管理大師」、「思聰舔我不得就錘我」、「吳秀波之談戀愛(ài)么,能坐牢的那種」……
除了使用 Redis 緩存避免直接訪問(wèn)數(shù)據(jù)庫(kù)以外,還會(huì)加更多的cache 層,比如采用 Memcachced 作為熱點(diǎn)數(shù)據(jù)的本地緩存:
先去 Memcachced中查詢數(shù)據(jù),命中直接返回。
Memcachced 未命中,則再?gòu)?Redis 查詢,命中則返回?cái)?shù)據(jù),并在 Memcachced 保存這個(gè)數(shù)據(jù)。
Redis 未命中,則去 MySQL中查詢,并依次設(shè)置到 Redis 和 Memcachced中。
訪問(wèn)本地內(nèi)存的的性能必然比通過(guò)網(wǎng)絡(luò)訪問(wèn) Redis 快,所以這種模式可以極大地減少獲取數(shù)據(jù)的延遲,并且可以減少 Redis 的負(fù)載,提高性能。
訪問(wèn) Redis 獲取數(shù)據(jù),服務(wù)器響應(yīng)。
查詢Redis
使用客戶端緩存,應(yīng)用程序?qū)@取的熱門的數(shù)據(jù)存儲(chǔ)在應(yīng)用程序中,無(wú)需再次通過(guò)網(wǎng)絡(luò)訪問(wèn) Redis。
應(yīng)該緩存什么
- 我們不應(yīng)該緩存不斷變化的鍵。
- 我們不該緩存很少請(qǐng)求的鍵。
- 我們希望緩存經(jīng)常請(qǐng)求并以合理速率更改的鍵。對(duì)于沒(méi)有穩(wěn)定變化速度的例子,比如不斷被INCR修改的全局計(jì)數(shù)器,就不應(yīng)該緩存。
- 客戶端緩存實(shí)現(xiàn)原理
客戶端緩存實(shí)現(xiàn)原理
碼老濕, Redis 中的數(shù)據(jù)修改或者失效了,如何及時(shí)同步告知客戶端失效了呢?自己實(shí)現(xiàn)也太復(fù)雜了。
Redis 實(shí)現(xiàn)的是一個(gè)服務(wù)端協(xié)助的客戶端緩存,叫做tracking。客戶端緩存的命令是:
- CLIENT TRACKING ON|OFF [REDIRECT client-id] [PREFIX prefix] [BCAST] [OPTIN] [OPTOUT] [NOLOOP]
Redis 6.0 實(shí)現(xiàn) Tracking 功能提供了兩種模式解決這個(gè)問(wèn)題,分別是使用RESP3 協(xié)議版本的普通模式和廣播模式,以及使用 RESP2 協(xié)議版本的轉(zhuǎn)發(fā)模式。
普通模式
當(dāng)tracking開(kāi)啟時(shí), Redis會(huì)「記住」每個(gè)客戶端請(qǐng)求的 key,當(dāng) key的值發(fā)現(xiàn)變化時(shí)會(huì)發(fā)送失效信息給客戶端 (invalidation message)。
失效信息可以通過(guò) RESP3協(xié)議發(fā)送給請(qǐng)求的客戶端,或者轉(zhuǎn)發(fā)給一個(gè)不同的連接 (支持 RESP2 + Pub/Sub) 的客戶端。
Server 端將 Client 訪問(wèn)的 key以及該 key 對(duì)應(yīng)的客戶端 ID 列表信息存儲(chǔ)在全局唯一的表(TrackingTable),當(dāng)表滿了,回移除最老的記錄,同時(shí)觸發(fā)該記錄已過(guò)期的通知給客戶端。
每個(gè) Redis 客戶端又有一個(gè)唯一的數(shù)字 ID,TrackingTable 存儲(chǔ)著每一個(gè) Client ID,當(dāng)連接斷開(kāi)后,清除該 ID 對(duì)應(yīng)的記錄。
TrackingTable 表中記錄的 Key 信息不考慮是哪個(gè) database 的,雖然訪問(wèn)的是 db1 的 key,db2 同名 key 修改時(shí)會(huì)客戶端收到過(guò)期提示,但這樣做會(huì)減少系統(tǒng)的復(fù)雜性,以及表的存儲(chǔ)數(shù)據(jù)量。
碼老濕,可以說(shuō)下這個(gè) TrackingTable 原理么?
Redis 服務(wù)端使用 TrackingTable存儲(chǔ)普通模式的客戶端數(shù)據(jù),它的數(shù)據(jù)類型是基數(shù)樹(shù) ( radix tree)。
基數(shù)樹(shù)是針對(duì)稀疏的長(zhǎng)整型數(shù)據(jù)查找的多叉搜索樹(shù),能快速且節(jié)省空間的完映射。
Redis 用它存儲(chǔ)鍵的指針和客戶端 ID 的映射關(guān)系。因?yàn)殒I對(duì)象的指針就是內(nèi)存地址,也就是長(zhǎng)整型數(shù)據(jù)。客戶端緩存的相關(guān)操作就是對(duì)該數(shù)據(jù)的增刪改查:
圖片來(lái)源-程序員厲小冰
注意
服務(wù)端對(duì)于記錄的 key 只會(huì)報(bào)告一次 invalidate 消息,也就是說(shuō),服務(wù)端在給客戶端發(fā)送過(guò)一次 invalidate 消息后,如果 key 再被修改,此時(shí),服務(wù)端就不會(huì)再次給客戶端發(fā)送 invalidate 消息。
只有下次客戶端再次執(zhí)行只讀命令被 track,才會(huì)進(jìn)行下一次消息通知 。
客戶端默認(rèn)不開(kāi)啟 track 模式,我們需要在獲取執(zhí)行指令之前執(zhí)行開(kāi)啟命令:
- CLIENT TRACKING ON|OFF
- +OK
- GET user:211
- $3
- 公眾號(hào):碼哥字節(jié)
廣播模式(BCAST)
當(dāng)廣播模式 (broadcasting) 開(kāi)啟時(shí),服務(wù)器不會(huì)記住給定客戶端訪問(wèn)了哪些鍵,因此這種模式在服務(wù)器端根本不消耗任何內(nèi)存。
在這個(gè)模式下,服務(wù)端會(huì)給客戶端廣播所有 key 的失效情況,如果 key 被頻繁修改,服務(wù)端會(huì)發(fā)送大量的失效廣播消息,這就會(huì)消耗大量的網(wǎng)絡(luò)帶寬資源。
所以,在實(shí)際應(yīng)用中,我們?cè)O(shè)置讓客戶端注冊(cè)只跟蹤指定前綴的 key,當(dāng)注冊(cè)跟蹤的 key 前綴匹配被修改,服務(wù)端就會(huì)把失效消息廣播給所有關(guān)注這個(gè) key前綴的客戶端。
- client tracking on bcast prefix user
這種監(jiān)測(cè)帶有前綴的 key 的廣播模式,和我們對(duì) key 的命名規(guī)范非常匹配。我們?cè)趯?shí)際應(yīng)用時(shí),會(huì)給同一業(yè)務(wù)下的 key 設(shè)置相同的業(yè)務(wù)名前綴,所以,我們就可以非常方便地使用廣播模式。
圖片來(lái)源-程序員厲小冰
廣播模式與普通模式類似,Redis 使用 PrefixTable 存儲(chǔ)廣播模式下的客戶端數(shù)據(jù),它存儲(chǔ)**前綴字符串指針和(需要通知的 key 和客戶端 ID)**的映射關(guān)系。
轉(zhuǎn)發(fā)模式
普通模式與廣播模式,需要客戶端使用 RESP 3 協(xié)議,他是 Redis 6.0 新啟用的協(xié)議。
對(duì)于使用 RESP 2 協(xié)議的客戶端來(lái)說(shuō),實(shí)現(xiàn)客戶端緩存則需要另一種模式:重定向模式(redirect)。
RESP 2 無(wú)法直接 PUSH 失效消息,所以 需要另一個(gè)支持 RESP 3 協(xié)議的客戶端 告訴 Server 將失效消息通過(guò) Pus/Sub 通知給 RESP 2 客戶端。
在重定向模式下,想要獲得失效消息通知的客戶端,就需要執(zhí)行訂閱命令 SUBSCRIBE,專門訂閱用于發(fā)送失效消息的頻道 _redis_:invalidate。
同時(shí),再使用另外一個(gè)客戶端,執(zhí)行 CLIENT TRACKING 命令,設(shè)置服務(wù)端將失效消息轉(zhuǎn)發(fā)給使用 RESP 2 協(xié)議的客戶端。
圖片來(lái)源-程序員厲小冰
假設(shè)客戶端 B 想要獲取失效消息,但是客戶端 B 只支持 RESP 2 協(xié)議,客戶端 A 支持 RESP 3 協(xié)議。我們可以分別在客戶端 B 和 A 上執(zhí)行 SUBSCRIBE 和 CLIENT TRACKING,如下所示:
- //客戶端B執(zhí)行,客戶端 B 的 ID 號(hào)是 606
- SUBSCRIBE _redis_:invalidate
- //客戶端 A 執(zhí)行
- CLIENT TRACKING ON BCAST REDIRECT 606
B 客戶端就可以通過(guò) _redis_:invalidate 頻道獲取失效消息了。
本文轉(zhuǎn)載自微信公眾號(hào)「碼哥字節(jié)」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系碼哥字節(jié)公眾號(hào)。































