RedisConf2020之Redis客戶端緩存

來源:Ben Malec from Paylocity and RedisConf 2020 organized by Redis Labs

翻譯:Wen Hui

轉載:中間件小哥

這篇文章中我們介紹如何使用Redis 6中關于客戶端緩存的支持來設計我們的客戶端緩存機制。我們首先來看一個典型的web應用如下:

image

在loadbalancer后面我們有多個web服務器,并與相同的SQL數據庫相連接。另外,在每個web服務器中,我們有多個服務器端緩存用來在服務器端緩存SQL數據庫中的數據。

我們這樣設計的目的是避免每次數據讀操作都訪問數據庫從而帶來較高的系統延時。但是,這種設計模式帶來一個主要問題是如果其中一個web服務器接收到更新數據的請求,會更新數據庫中的數據,以及這個服務器中的服務器緩存,但是其他的web服務器中會繼續緩存舊的數據,從而帶來數據不一致的問題。我們可以想到有多個解決方案來解決這個問題,首先一種比較常見的方案是更新數據的web服務器可以將數據更新的請求廣播到其他的web服務器中。但是這種方式會帶來以下兩個主要問題:

1. 會很大程度上增加系統網絡的負載。

2. 會導致競態條件(race condition)以及其他一些問題。例如如果兩個web服務器同時更新同一個數據,那么系統網絡無法保證這兩個更新請求到達其他服務器的先后順序。

針對以上問題,一個常見的解決方案是我們可以將服務器端緩存替換成Redis,如下圖所示:

image

這樣做的好處是:

1. Redis比其他后端數據庫存儲要快許多。

2. 完全可以解決競態條件或數據不一致的問題,因為多個web服務器共享了redis實例,所以客戶端每次都會得到正確的結果。

但這樣也帶來了web服務器與Redis通信的網絡延時的問題。因為在一般情況下,內存訪問速度很快,所以網絡延時很容易成為這種設計的瓶頸。

如果我們綜合了以上兩種設計,我們會得到以下設計方案:

image

在這里,我們保留服務器端緩存,并在redis中數據改變的情況下,通過redis的廣播機制來更新其他web服務器中的緩存。整體設計如下:

1. Redis始終是系統緩存的單一數據源。

2. 當Redis緩存的值更新后,通過Redis的發布訂閱連接來更新其他web服務器中的緩存。

3. 在其他web服務器收到更新緩存的消息以后,會使本地服務器端緩存失效,然后再下次接收到讀數據請求的時候訪問redis實例以拿到更新后的值。

4. 這樣設計不僅可以保持數據一致性并且可以使用服務器端緩存以降低系統延時。

5. 在多個服務器同時更新的情況下,因為Redis是單一數據源,所以所有的服務器端緩存都會得到正確的值。

6. Paylocity做了進一步的優化,沒有將整個鍵來廣播給其他web服務器,而是只廣播鍵的hash值,這樣可以進一步降低網絡負載。但同時也增加一些程序的復雜度。

作者在Redis Conf 2018 對這種解決方案做了演講,但也收到Redis 作者Savatore提到的一些潛在的問題:

1. 所有的更新操作必須通過web服務器中的緩存邏輯,如果直接更改redis的話其他web服務器端不會收到更新。

2. 所有更新都會被廣播到所有的web服務器中,無論web服務器中是否緩存過更新的鍵。

3. 如果Redis內核可以為客戶端緩存的逐出提供幫助將是一個更好的方案。

到了Redis 6.0版本,redis實現了針對客戶端緩存的追蹤機制,具體特性如下:

1. 在Redis中添加了關于客戶端緩存追蹤的新命令。

2. Opt in:Redis客戶端可以選擇是否啟用客戶端追蹤。

3. 兩種模式: 默認和廣播模式。

4. Redis會記錄鍵值的改動,并記錄哪個客戶端對哪個鍵值感興趣。

5. 當鍵值改動后,Redis會發送給啟用緩存追蹤的客戶端發送緩存無效信息。

6. 客戶端會逐出特定的客戶端緩存,下一次的請求將訪問Redis以獲取數據。

下面具體介紹Redis 客戶端緩存追蹤的具體模式:

1. 默認模式

Redis 命令:CLIENT TRACKING ON

在默認模式下, Redis會顯式的記住每個客戶端感興趣哪個特定的鍵,如果鍵被更新時,Redis只給那些對這個鍵感興趣的客戶端發送緩存無效的信息。

優點:

可以最大限度利用網絡帶寬,不會有多余的消息發送給沒有緩存過這個鍵的客戶端。

缺點:

對于Redis服務器來說記住每個客戶端感興趣的鍵會導致使用更多的內存。

如果我們有幾千個客戶端和幾百萬個鍵,這種方式會消耗非常大的內存資源。

如果redis需要清理追蹤部分的內存的話,需要給客戶端發送緩存無效的消息, 即使特定的鍵值沒有被改變。

2. 廣播模式

Redis命令: CLIENT TRACKING ON BCAST

在廣播模式下,Redis會發送給啟用客戶端緩存追蹤的所有客戶端發送緩存失效消息,無論特定的鍵是否緩存在客戶端中。

優點:

沒有在Redis服務器實例中顯著使用內存。

缺點:

需要更多的網絡帶寬。

3. 帶注冊前綴的廣播模式

Redis命令: CLIENT TRACKING ON BCAST PREFIX key_prefix_value

在廣播模式下,可以通過注冊鍵前綴方式來限制在鍵被更新的情況下,只有注冊特定鍵前綴的客戶端才會收到緩存失效的消息。

需要注意的地方是:

1. 鍵的名字需要仔細定義,因為這樣可以減少緩存失效消息的數量。

2. 多個鍵前綴可以被同個客戶端指定。

3. 可以通過鍵前綴來告訴redis哪些鍵會被客戶端緩存而那些不會,例如:

clientSide:MyAppCode:keyname和MyAppCode:keyname。

4.默認模式中的Optin 模式

Redis命令:CLIENT TRACKING ON OPTIN

在Opt in模式下,客戶端將收到所指定的鍵緩存失效的消息,在默認模式中,所有鍵是默認注冊的,但在Opt in模式下,需要顯式指定哪些鍵需要被注冊。指定鍵被注冊的命令是CLIENT CACHING YES,接下來的一個讀請求的鍵將會被注冊在Redis服務器端的追蹤表里,當這個鍵被更新時客戶端會收到緩存失效消息。

例子如下:

CLIENT CACHING YES

+OK

GET MYKEY1

$8

MyValue6

現在如果MYKEY1的值被改變,則客戶端會收到緩存失效消息。

5 默認模式中的Opt Out模式

Redis 命令: CLIENT TRACKING ON OPTOUT

和OPTIN 模式相反,在OPTOUT模式下客戶端鍵默認會被追蹤,需要顯式指定哪些鍵不需要被追蹤。

如果需要關閉特定鍵的追蹤,需要向Redis發送讀請求之前使用CLIENT CACHING NO命令。

例子如下:

CLIENT CACHING NO

+OK

GET MYKEY2

$8

MyValue2

現在如果MYKEY2的值被改變,客戶端不會收到緩存失效的消息。

在介紹完客戶端緩存追蹤的幾種模式后,下一個問題就是在何種情況下需要使用何種模式。這個問題實際上跟具體的應用需求有關,實際上是在Redis內存使用和整個系統網絡資源上做取舍。

你的應用是否有很多緩存更新的場景?如果不是的話可以選用廣播模式,因為在這種場景下大部分的鍵不會被更新,所以沒有必要在Redis端記住所有的鍵信息。

相反的,如果應用相對來說有很多更新緩存鍵的應用場景,那么可以選用默認模式,尤其當有很多客戶端,但每個客戶端緩存鍵的數量相對較少的情況下。默認模式是最好的選擇。

另外在我們的設計中,我們會把CLIENT ID 也放到緩存無效信息中,這樣特定客戶端會忽略自己觸發的的緩存失效消息。(注在新版本的Redis 6.0.4中,可以使用NOLOOP來達到同樣的效果)

另外需要留意的是客戶端追蹤可以指定另一個REDIRECT選項,這個選項主要是為RESP2(舊版本)協議的客戶端提供的。因為在舊版本的協議中,不支持從Redis服務器端向客戶端推送消息。所以這個選項的作用是將緩存失效的消息推送到額外指定的客戶端。

具體的使用方法是:

1. 在客戶端啟用客戶端緩存前,創建一個新的客戶端,使用CLIENT ID命令記錄下這個客戶端的ID,讓后使用SUBSCRIBE redis:invalidate來訂閱緩存失效消息的頻道。

2. 在啟用客戶端緩存的時候使用這個客戶端ID來接收無效消息,例如如果ID為5,則使用CLIENT TRACKING YES REDIRECT 5。

3. 這樣緩存無效消息將發送到這個指定客戶端中,但是需要注意的是這種方式會潛在帶來潛在的競態條件。因為如果同時有另外客戶端更新Redis中的鍵數據,無法保證客戶端收到緩存失效消息的時間。

在新版本的Redis RESP3協議中支持從Redis服務器端推送消息,但在RESP2協議中只支持客戶端發送請求Redis服務器端處理并回復。

1. 現在客戶端可以使用兩種不同版本的協議。

2. 不需要創建新的TCP連接來接收緩存失效消息。創建新的連接對Paylocity來說是一個很大的問題,因為我們使用多個Redis集群,每個客戶端保留向集群中每一個節點的連接。

3. 但現在RESP3協議的主要問題是大部分的客戶端庫都沒有支持這個協議。

下面我們討論使用客戶端追蹤的應用具體實現步驟:

1. 在客戶端中,創建客戶端緩存并連接Redis

2. 使用CLIENT TRACKING ON 來啟用追蹤。

3. 更新數據時,更新Redis 和相應的客戶端緩存。需要記住的是Redis是單一數據來源。

4. 在讀取數據過程中,先從客戶端緩存中讀取,如果未找到數據則在Redis中讀取。如果在Redis中找到數據,則更新客戶端本地緩存,這樣的話下個請求將會通過本地緩存拿到新的數據。同時也需要從Redis中讀取TTL并設置本地緩存過期時間。

5. 監聽連接的無效消息頻道,如果客戶端接收到Redis發送的緩存失效消息,則更新本地緩存。

Paylocity的計劃:

利用Redis的客戶端追蹤功能:

像之前介紹的那樣,我們有比較少的web服務器,而且在大多數情況下鍵值不會經常改變,所以廣播模式比較適用于這種場景。

廣播前綴的方式非常適用于我們的場景,因為我們會創建一個大的Redis集群并共享給各個應用。所以我們使用應用代號來當作BROADCAST的前綴。

使用RESP3客戶端:

1. 可以極大的減少總的Redis連接數

2. 目前我們使用StackExchange Redis客戶端,一個非常好的客戶端,只是不確定以后對RESP3協議的支持。

3. 如果我們自己實現redis客戶端的話也不會有大的問題,因為我們只需要支持GET,SET 和接收緩存失效消息。

以下作者提供了使用Redis客戶端緩存支持的例子:

https://github.com/bmalec/RedisClientTrackingDemo

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380