Redis 6.0 新特性篇:深度剖析客戶端快取(Client side caching)原理與效能

碼哥位元組發表於2021-11-08
碼老溼,上次你講解了 Redis 多執行緒模型,這次我想知道客戶端快取(Client side caching)技術,他的英文名叫: Redis server-assisted client side caching ,可以說說麼?
我不是嫖客,看完我會點贊、再看、分享的。

別裝逼了,還整英文,咋不上天,做人要說話算數喲,不然半夜尿褲子。在說這個之前,碼哥先給讀者送一段寄語作為開篇。

開篇寄語

不要吝嗇你的讚美,如果別人做的很好,就給他正反饋,這也是一種利他。

另外,少關注用「讚美」投票的事物,而多關注用「交易」投票的事物。

判斷一個人是否牛逼,不是看網上有多少人讚美他,而是看有多少人願意跟他發生交易、讚賞、支付、下單。

因為讚美太廉價,而願意與他發生交易,才是真正的信任。

為啥需要客戶端快取

RedisTracking Feature 的實現程式碼在: https://github.com/antirez/redis/blob/unstable/src/tracking.c

很多公司使用 Redis 做快取系統,並且很好的提高了資料訪問的效能,為了進一步應對熱點資料,還是會在 Redis 的 Client 端快取一部分熱點資料,用來應對「吃瓜事件」。

比如,「這該死的 996 福報」、「吳亦凡之大方牢房」、「時間管理大師」、「思聰舔我不得就錘我」、「吳秀波之談戀愛麼,能坐牢的那種」……

除了使用 Redis 快取避免直接訪問資料庫以外,還會加更多的 cache 層,比如採用 Memcachced 作為熱點資料的本地快取:

  1. 先去 Memcachced 中查詢資料,命中直接返回。
  2. Memcachced 未命中,則再從 Redis 查詢,命中則返回資料,並在 Memcachced 儲存這個資料。
  3. Redis 未命中,則去 MySQL中查詢,並依次設定到 Redis 和 Memcachced中。

訪問本地記憶體的的效能必然比通過網路訪問 Redis 快,所以這種模式可以極大地減少獲取資料的延遲,並且可以減少 Redis 的負載,提高效能

  1. 訪問 Redis 獲取資料,伺服器響應。

查詢Redis

  1. 使用客戶端快取,應用程式將獲取的熱門的資料儲存在用用程式中,無需再次通過網路訪問 Redis。

應該快取什麼

  • 我們不應該快取不斷變化的鍵。
  • 我們不該快取很少請求的鍵。
  • 我們希望快取經常請求並以合理速率更改的鍵。對於沒有穩定變化速度的例子,比如不斷被INCR修改的全域性計數器,就不應該快取。

客戶端快取實現原理

碼老溼, Redis 中的資料修改或者失效了,如何及時同步告知客戶端失效了呢?自己實現也太複雜了。

Redis 實現的是一個服務端協助的客戶端快取,叫做tracking。客戶端快取的命令是:

CLIENT TRACKING ON|OFF [REDIRECT client-id] [PREFIX prefix] [BCAST] [OPTIN] [OPTOUT] [NOLOOP]

Redis 6.0 實現 Tracking 功能提供了兩種模式解決這個問題,分別是使用RESP3 協議版本的普通模式和廣播模式,以及使用 RESP2 協議版本的轉發模式。

來源於程式設計師厲小冰*

普通模式

tracking開啟時, Redis 會「記住」每個客戶端請求的 key,當 key 的值發現變化時會傳送失效資訊給客戶端 (invalidation message)。

失效資訊可以通過 RESP3 協議傳送給請求的客戶端,或者轉發給一個不同的連線 (支援 RESP2 + Pub/Sub) 的客戶端。

  • Server 端將 Client 訪問的 key以及該 key 對應的客戶端 ID 列表資訊儲存在全域性唯一的表(TrackingTable),當表滿了,回移除最老的記錄,同時觸發該記錄已過期的通知給客戶端。
  • 每個 Redis 客戶端又有一個唯一的數字 ID,TrackingTable 儲存著每一個 Client ID,當連線斷開後,清除該 ID 對應的記錄。
  • TrackingTable 表中記錄的 Key 資訊不考慮是哪個 database 的,雖然訪問的是 db1 的 key,db2 同名 key 修改時會客戶端收到過期提示,但這樣做會減少系統的複雜性,以及表的儲存資料量。
碼老溼,可以說下這個 TrackingTable 原理麼?

Redis 服務端使用 TrackingTable 儲存普通模式的客戶端資料,它的資料型別是基數樹 ( radix tree)。

基數樹是針對稀疏的長整型資料查詢的多叉搜尋樹,能快速且節省空間的完對映。

Redis 用它儲存鍵的指標客戶端 ID 的對映關係。因為鍵物件的指標就是記憶體地址,也就是長整型資料。客戶端快取的相關操作就是對該資料的增刪改查:

圖片來源-程式設計師厲小冰

注意

服務端對於記錄的 key 只會報告一次 invalidate 訊息,也就是說,服務端在給客戶端傳送過一次 invalidate 訊息後,如果 key 再被修改,此時,服務端就不會再次給客戶端傳送 invalidate 訊息。

只有下次客戶端再次執行只讀命令被 track,才會進行下一次訊息通知

客戶端預設不開啟 track 模式,我們需要在獲取執行指令之前執行開啟命令:

CLIENT TRACKING ON|OFF
+OK
GET user:211
$3
公眾號:碼哥位元組

廣播模式(BCAST)

當廣播模式 (broadcasting) 開啟時,伺服器不會記住給定客戶端訪問了哪些鍵,因此這種模式在伺服器端根本不消耗任何記憶體。

在這個模式下,服務端會給客戶端廣播所有 key 的失效情況,如果 key 被頻繁修改,服務端會傳送大量的失效廣播訊息,這就會消耗大量的網路頻寬資源。

所以,在實際應用中,我們設定讓客戶端註冊只跟蹤指定字首的 key,當註冊跟蹤的 key 字首匹配被修改,服務端就會把失效訊息廣播給所有關注這個 key字首的客戶端。

client tracking on bcast prefix user

這種監測帶有字首的 key 的廣播模式,和我們對 key 的命名規範非常匹配。我們在實際應用時,會給同一業務下的 key 設定相同的業務名字首,所以,我們就可以非常方便地使用廣播模式。

圖片來源-程式設計師厲小冰

廣播模式與普通模式類似,Redis 使用 PrefixTable 儲存廣播模式下的客戶端資料,它儲存字首字串指標和(需要通知的 key 和客戶端 ID)的對映關係。

轉發模式

普通模式與廣播模式,需要客戶端使用 RESP 3 協議,他是 Redis 6.0 新啟用的協議。

對於使用 RESP 2 協議的客戶端來說,實現客戶端快取則需要另一種模式:重定向模式(redirect)。

RESP 2 無法直接 PUSH 失效訊息,所以 需要另一個支援 RESP 3 協議的客戶端 告訴 Server 將失效訊息通過 Pus/Sub 通知給 RESP 2 客戶端。

在重定向模式下,想要獲得失效訊息通知的客戶端,就需要執行訂閱命令 SUBSCRIBE,專門訂閱用於傳送失效訊息的頻道 _redis_:invalidate

同時,再使用另外一個客戶端,執行 CLIENT TRACKING 命令,設定服務端將失效訊息轉發給使用 RESP 2 協議的客戶端。

圖片來源-程式設計師厲小冰

假設客戶端 B 想要獲取失效訊息,但是客戶端 B 只支援 RESP 2 協議,客戶端 A 支援 RESP 3 協議。我們可以分別在客戶端 B 和 A 上執行 SUBSCRIBE 和 CLIENT TRACKING,如下所示:

//客戶端B執行,客戶端 B 的 ID 號是 606
SUBSCRIBE _redis_:invalidate

//客戶端 A 執行
CLIENT TRACKING ON BCAST REDIRECT 606

B 客戶端就可以通過 _redis_:invalidate 頻道獲取失效訊息了。

熱門推薦

Redis 新特性篇:多執行緒模型解讀

Redis 實戰篇:通過 Geo 型別實現附近的人邂逅女神

Redis 麵霸篇:從高頻問題透視核心原理

相關文章