天天看點

實踐篇 -- Redis用戶端緩存在SpringBoot應用的探究

本文探究Redis最新特性--用戶端緩存在SpringBoot上的應用實戰。

Redis用戶端緩存機制基于Redis Tracking機制實作的。我們先了解一下Redis Tracking機制。

Redis由于速度快、性能高,常常作為MySQL等傳統資料庫的緩存資料庫。但由于Redis是遠端服務,查詢Redis需要通過網絡請求,在高并發查詢情景中難免造成性能損耗。是以,高并發應用通常引入本地緩存,在查詢Redis前先檢查本地緩存是否存在資料。

假如使用MySQL存儲資料,那麼資料查詢流程下圖所示。

實踐篇 -- Redis用戶端緩存在SpringBoot應用的探究

引入多端緩存後,修改資料時,各資料緩存端如何保證資料一緻是一個難題。通常的做法是修改MySQL資料,并删除Redis緩存、本地緩存。當使用者發現緩存不存在時,會重新查詢MySQL資料,并設定Redis緩存、本地緩存。

在分布式系統中,某個節點修改資料後不僅要删除目前節點的本地緩存,還需要發送請求給叢集中的其他節點,要求它們删除該資料的本地緩存,如下圖所示。如果分布式系統中節點很多,那麼該操作會造成不少性能損耗。

實踐篇 -- Redis用戶端緩存在SpringBoot應用的探究

為此,Redis 6提供了Redis Tracking機制,對該緩存方案進行了優化。開啟Redis Tracking後,Redis伺服器會記錄用戶端查詢的所有鍵,并在這些鍵發生變更後,發送失效消息通知用戶端這些鍵已變更,這時用戶端需要将這些鍵的本地緩存删除。基于Redis Tracking機制,某個節點修改資料後,不需要再在叢集廣播“删除本地緩存”的請求,進而降低了系統複雜度,并提高了性能。

下表展示了Redis Tracking的基本使用

實踐篇 -- Redis用戶端緩存在SpringBoot應用的探究

(1)為了支援Redis伺服器推送消息,Redis在RESP2協定上進行了擴充,實作了RESP3協定。HELLO 3指令表示用戶端與Redis伺服器之間使用RESP3協定通信。

注意:Redis 6.0提供了Redis Tracking機制,但該版本的redis-cli并不支援RESP3協定,是以這裡需要使用Redis 6.2版本的redis-cli進行示範。

(2)CLIENT TRACKING on指令的作用是開啟Redis Tracking機制,此後Redis伺服器會記錄用戶端查詢的鍵,并在這些鍵變更後推送失效消息通知用戶端。失效消息以invalidate開頭,後面是失效鍵數組。

上表中的用戶端 client1 查詢了鍵 score 後,用戶端 client2 修改了該鍵,這時 Redis 伺服器會馬上推送失效消息給用戶端 client1,但 redis-cli 不會直接展示它收到的推送消息,而是在下一個請求傳回後再展示該消息,是以 client1 重新發送了一個 PING請求。

上面使用的非廣播模式,另外,Redis Tracking還支援廣播模式。在廣播模式下,當變更的鍵以用戶端關注的字首開頭時,Redis伺服器會給所有關注了該字首的用戶端發送失效消息,不管用戶端之前是否查詢過這些鍵。

下表展示了如何使用Redis Tracking的廣播模式。

實踐篇 -- Redis用戶端緩存在SpringBoot應用的探究

說明一下CLIENT TRACKING指令中的兩個參數:

BCAST參數:啟用廣播模式。

PREFIX參數:聲明用戶端關注的字首,即用戶端隻關注cache開頭的鍵。

強調一下非廣播模式與廣播模式的差別:

非廣播模式:Redis伺服器記錄客戶查詢過的鍵,當這些鍵發生變化時,Redis發送失效消息給用戶端。

廣播模式:Redis伺服器不記錄客戶查詢過的鍵,當變更的鍵以用戶端關注的字首開頭時,Redis就會發送失效消息給用戶端。

關于Redis Tracking的更多内容,我已經在新書《Redis核心原理與實踐》中詳細分析,這裡不再贅述。

既然Redis提供了Tracking機制,那麼用戶端就可以基于該機制實作用戶端緩存了。

Lettuce(6.1.5版本)已經支援Redis用戶端緩存(單機模式下),使用CacheFrontend類可以實作用戶端緩存。

建構RedisClient。

建構CacheFrontend。

ClientSideCaching.enable開啟用戶端緩存,即發送“CLIENT TRACKING”指令給Redis伺服器,要求Redis開啟Tracking機制。

最後一個參數指定了Redis Tracking的模式,這裡用的是最簡單的非廣播模式。

這裡可以看到,通過Map儲存用戶端緩存的内容。

重複查詢同一個值,檢視緩存是否生效。

我們可以通過Redis的Monitor指令監控Redis服務收到的指令,使用該指令就可以看到,開啟用戶端緩存後,Lettuce不會重複查詢同一個鍵。

而且我們修改這個鍵後,Lettuce會重新查詢這個鍵的最新值。

通過Redis的Client List指令可以檢視連接配接的資訊

<code>flags=t</code>代表這個連接配接啟動了Tracking機制。

那麼如何在SpringBoot上使用呢?請看下面的例子

其實也簡單,通過RedisConnectionFactory擷取一個StatefulRedisConnection連接配接,就可以建立CacheFrontend了。

這裡RedisClient#connect方法會建立一個新的連接配接,這樣可以将使用用戶端緩存、不使用用戶端緩存的連接配接區分。

Lettuce的StatefulRedisConnection類還提供了addListener方法,可以設定回調方法處理Redis推送的消息。

利用該方法,我們可以将Guava的緩存與Redis用戶端緩存結合

擷取Redis連接配接。

建立Guava緩存類LoadingCache,該緩存類如果發現資料不存在,則查詢Redis。

開啟Redis用戶端緩存。

添加回調函數,如果收到Redis發送的失效消息,則清除Guava緩存。

上面說的應用必須在Redis單機模式下(或者主從、Sentinel模式),遺憾的是,

目前發現Lettuce(6.1.5版本)還沒有支援Redis Cluster下的用戶端緩存,

簡單看了一下源碼,目前發現如下原因:

Cluster模式下,Redis指令需要根據指令的鍵,重定向到鍵的存儲節點執行。

而對于“CLIENT TRACKING”這個沒有鍵的指令,Lettuce并沒有将它發送給Cluster中所有的節點,而是将它發送給一個固定的預設的節點(可檢視ClusterDistributionChannelWriter類),是以通過StatefulRedisClusterConnection調用RedisAdvancedClusterCommands.clientTracking方法并沒有開啟Redis服務的Tracking機制。

這個其實也可以修改,有時間再研究一下。

那麼單機模式下,Lettuce的用戶端緩存就真的沒有問題了嗎?

仔細思考一下Redis Tracking的設計,發現使用Redis用戶端緩存有兩個點需要關注:

開啟用戶端緩存後,Redis連接配接不能斷開。

如果Redis連接配接斷了,并且用戶端自動重連,那麼新的連接配接是沒有開啟Tracking機制的,該連接配接查詢的鍵不會受到失效消息,後果很嚴重。

同樣,開啟Tracking的連接配接和查詢緩存鍵的連接配接必須是同一個,不能使用A連接配接開啟Tracking機制,使用B連接配接去查詢緩存鍵(是以用戶端不能使用連接配接池)。

Redis伺服器可以設定timeout配置,自動超過該配置沒有發送請求的連接配接。

而Lettuce有自動重連機制,重連後的連接配接将收不到失效消息。

有兩個解決思路:

(1)實作Lettuce心跳機制,定時發送PING指令以維持連接配接。

(2)即使使用心跳機制,Redis連接配接依然可能斷開(網絡跳動等原因),可以修改自動重連機制(ReconnectionHandler),增加如下邏輯:如果連接配接原來開啟了Tracking機制,則重連後需要自動開啟Tracking機制。

需要注意,如果使用的是非廣播模式,需要清空舊連接配接緩存的資料,因為連接配接已經變更,Redis伺服器不會将舊連接配接的失效消息發送給新連接配接。

啟用緩存的連接配接與未啟動緩存的連接配接應該區分。

這點比較簡單,上例例子中都使用RedisClient#connect方法建立一個新的連接配接,專用于用戶端緩存。

用戶端緩存是一個強大的功能,需要我們去用好它。可惜目前暫時還沒有完善的Java用戶端支援,本書說了我的一些分析與思路,歡迎探讨。我後續會關注繼續Lettuce的更新,如果Lettuce提供了完善的Redis用戶端緩存支援,再更新本文。

關于Redis Tracking的詳細使用與實作原理,我在新書《Redis核心原理與實踐》做了詳盡分析,文章最後,介紹一下這本書:

本書通過深入分析Redis 6.0源碼,總結了Redis核心功能的設計與實作。通過閱讀本書,讀者可以深入了解Redis内部機制及最新特性,并學習到Redis相關的資料結構與算法、Unix程式設計、存儲系統設計,分布式系統架構等一系列知識。

經過該書編輯同意,我會繼續在個人技術公衆号(binecy)釋出書中部分章節内容,作為書的預覽内容,歡迎大家查閱,謝謝。

語雀平台預覽:《Redis核心原理與實踐》

京東連結

繼續閱讀