[redis進階六]詳解redis作為緩存分布式鎖

目錄

一? 什么是緩存

緩存總結板書:

二? 使?Redis作為緩存

三??緩存的更新策略

1) 定期?成

?2) 實時?成

四? 面試重點:緩存預熱,緩存穿透,緩存雪崩 和緩存擊穿

1)緩存預熱

2)緩存穿透

3)緩存雪崩

4)緩存擊穿

五? 分布式鎖

板書:

1)什么是分布式鎖

2)分布式鎖的基礎實現

3)引?過期時間

4)引?校驗id

5)引?lua

6)引?watchdog(看?狗)

7) 引?Redlock算法

六???其他功能


一? 什么是緩存

緩存總結板書:

緩存(cache)是計算機中的?個經典的概念.在很多場景中都會涉及到.
核?思路就是把?些常?的數據放到觸?可及(訪問速度更快)的地?,?便隨時讀取.

對于計算機硬件來說,往往訪問速度越快的設備,成本越?,存儲空間越?.
緩存是更快,但是空間上往往是不?的.因此?部分的時候,緩存只放?些熱點數據(訪問頻繁的數據),
就?常有?了.

二? 使?Redis作為緩存

在?個?站中,我們經常會使?關系型數據庫(?如MySQL)來存儲數據.
關系型數據庫雖然功能強?,但是有?個很?的缺陷,就是性能不?.(換??之,進??次查詢操作消耗的系統資源較多).

因此,如果訪問數據庫的并發量?較?,對于數據庫的壓?是很?的,很容易就會使數據庫服務器宕機.

如何讓數據庫能夠承擔更?的并發量呢?核?思路主要是兩個:

?

  • 開源:引?更多的機器,部署更多的數據庫實例,構成數據庫集群.(主從復制,分庫分表等...)
  • 節流:引?緩存,使?其他的?式保存經常訪問的熱點數據,從?降低直接訪問數據庫的請求數量.

實際開發中,這兩種?案往往是會搭配使?的.

Redis 就是?個?來作為數據庫緩存的常??案.

就像?個"護盾"?樣,把MySQL給罩住了.

1) 客戶端訪問業務服務器,發起查詢請求.

2) 業務服務器先查詢Redis,看想要的數據是否在Redis中存在.

??????????如果已經在Redis中存在了,就直接返回.此時不必訪問MySQL了.

? ? ? ? ??如果在Redis中不存在,再查詢MySQL.

按照上述討論的"??定律",只需要在Redis中放20%的熱點數據,就可以使80%的請求不再真正查詢數據庫了.

當然,實踐中究竟是"??",還是"?九",還是"三七",這個情況可能會根據業務場景的不同,存在差
異.但是?少絕?多數情況下,使?緩存都能夠??提升整體的訪問效率,降低數據庫的壓?.

三??緩存的更新策略

接下來還有?個重要的問題,到底哪些數據才是"熱點數據"呢?

1) 定期?成

每隔?定的周期(?如?天/?周/?個?),對于訪問的數據頻次進?統計.挑選出訪問頻次最?的前N%的數據.

這種做法實時性較低.對于?些突然情況應對的并不好.

?如春節期間,"春晚"這樣的詞就會成為?常?頻的詞.?平時則很少會有?搜索"春晚".

?2) 實時?成

先給緩存設定容量上限(可以通過Redis配置?件的maxmemory?參數設定).
接下來把?戶每次查詢:

  • ?如果在Redis查到了,就直接返回.
  • ?如果Redis中不存在,就從數據庫查,把查到的結果同時也寫?Redis.

如果緩存已經滿了(達到上限),就觸發緩存淘汰策略,把?些"相對不那么熱?"的數據淘汰掉.
按照上述過程,持續?段時間之后Redis內部的數據?然就是"熱?數據"了.

通?的淘汰策略主要有以下?種:

下列策略并?局限于Redis,其他緩存也可以按這些策略展開.

1)FIFO (First In First Out) 先進先出
把緩存中存在時間最久的(也就是先來的數據)淘汰掉.


2)LRU(LeastRecentlyUsed)淘汰最久未使?的
記錄每個key的最近訪問時間.把最近訪問時間最?的key淘汰掉.

3)LFU(LeastFrequently Used)淘汰訪問次數最少的
記錄每個key最近?段時間的訪問次數.把訪問次數最少的淘汰掉.

4)Random隨機淘汰
從所有的key中抽取幸運?被隨機淘汰掉.

這?的淘汰策略,我們可以??實現.當然Redis也提供了內置的淘汰策略,也可以供我們直接使?.

Redis 內置的淘汰策略如下:

  • ?volatile-lru?當內存不?以容納新寫?數據時,從設置了過期時間的key中使?LRU(最近最少使?)算法進?淘汰
  • ?allkeys-lru?當內存不?以容納新寫?數據時,從所有key中使?LRU(最近最少使?)算法進?淘汰.
  • ?volatile-lfu?4.0版本新增,當內存不?以容納新寫?數據時,在過期的key中,使?LFU算法進?刪除key.
  • allkeys-lfu?4.0版本新增,當內存不?以容納新寫?數據時,從所有key中使?LFU算法進?淘汰.
  • ?volatile-random?當內存不?以容納新寫?數據時,從設置了過期時間的key中,隨機淘汰數據.
  • ?allkeys-random?當內存不?以容納新寫?數據時,從所有key中隨機淘汰數據.
  • ?volatile-ttl?在設置了過期時間的key中,根據過期時間進?淘汰,越早過期的優先被淘汰.
    ?(相當于FIFO,只不過是局限于過期的key)
  • noeviction?默認策略,當內存不?以容納新寫?數據時,新寫?操作會報錯

整體來說Redis提供的策略和我們上述介紹的通?策略是基本?致的.只不過Redis這?會針對"過期key" 和"全部key"做分別處理.

四? 面試重點:緩存預熱,緩存穿透,緩存雪崩 和緩存擊穿

1)緩存預熱

什么是緩存預熱?

使?Redis作為MySQL的緩存的時候,當Redis剛剛啟動,或者Redis?批key失效之后,此時由于
Redis ??相當于是空著的,沒啥緩存數據,那么MySQL就可能直接被訪問到,從?造成較?的壓?.
因此就需要提前把熱點數據準備好,直接寫?到Redis中.使Redis可以盡快為MySQL撐起保護傘.

熱點數據可以基于之前介紹的統計的?式?成即可.這份熱點數據不?定?得那么"準確",只要能幫助MySQL抵擋?部分請求即可.隨著程序運?的推移,緩存的熱點數據會逐漸?動調整,來更適應當前情況.

2)緩存穿透

什么是緩存穿透?

訪問的key在Redis和數據庫中都不存在.此時這樣的key不會被放到緩存上,后續如果仍然在訪問該
key, 依然會訪問到數據庫.這就會導致數據庫承擔的請求太多,壓?很?.
這種情況稱為 緩存穿透.

為何產??
原因可能有?種:

  • 業務設計不合理.?如缺少必要的參數校驗環節,導致?法的key也被進?查詢了.
  • 開發/運維誤操作.不??把部分數據從數據庫上誤刪了.
  • ?客惡意攻擊

如何解決?

  • 針對要查詢的參數進?嚴格的合法性校驗.?如要查詢的key是??的?機號,那么就需要校驗當前key 是否滿??個合法的?機號的格式.
  • 針對數據庫上也不存在的key,也存儲到Redis中,?如value就隨便設成?個"".避免后續頻繁訪問數據庫.
  • 使?布隆過濾器先判定key是否存在,再真正查詢.

3)緩存雪崩

什么是緩存雪崩?

短時間內?量的key在緩存上失效,導致數據庫壓?驟增,甚?直接宕機.

本來Redis是MySQL的?個護盾,幫MySQL抵擋了很多外部的壓?.?旦護盾突然失效了,MySQL
??承擔的壓?驟增,就可能直接崩潰.

為何產??

?規模key失效,可能性主要有兩種:

  • Redis掛了.
  • Redis上的?量的key同時過期

為啥會出現?量的key同時過期?
這種和可能是短時間內在Redis上緩存了?量的key,并且設定了相同的過期時間.

如何解決?

  • 部署?可?的Redis集群,并且完善監控報警體系.
  • 不給key設置過期時間或者設置過期時間的時候添加隨機時間因?.

4)緩存擊穿

什么是緩存擊穿?

為何產生?

相當于緩存雪崩的特殊情況.針對熱點key,突然過期了,導致?量的請求直接訪問到數據庫上,甚?引
起數據庫宕機.

如何解決:

  • 基于統計的?式發現熱點key,并設置永不過期.
  • 進?必要的服務降級.例如訪問數據庫的時候使?分布式鎖,限制同時請求數據庫的并發數.

五? 分布式鎖

板書:

1)什么是分布式鎖

在?個分布式的系統中,也會涉及到多個節點訪問同?個公共資源的情況.此時就需要通過鎖來做互斥控制,避免出現類似于"線程安全"的問題.
?java的synchronized或者C++的std::mutex,這樣的鎖都是只能在當前進程中?效,在分布式的這
種多個進程多個主機的場景下就?能為?了.
此時就需要使?到分布式鎖.

2)分布式鎖的基礎實現

思路?常簡單.本質上就是通過?個鍵值對來標識鎖的狀態.
舉個例?:考慮買票的場景,現在?站提供了若?個?次,每個?次的票數都是固定的.
現在存在多個服務器節點,都可能需要處理這個買票的邏輯:先查詢指定?次的余票,如果余票>0,則設置余票值-=1.

顯然上述的場景是存在"線程安全"問題的,需要使?鎖來控制.
否則就可能出現"超賣"的情況.

此時如何進?加鎖呢?我們可以在上述架構中引??個Redis,作為分布式鎖的管理器.

此時,如果買票服務器1嘗試買票,就需要先訪問Redis,在Redis上設置?個鍵值對.?如key就是?次,value隨便設置個值(?如1).


如果這個操作設置成功,就視為當前沒有節點對該001?次加鎖,就可以進?數據庫的讀寫操作.操作完成之后,再把Redis上剛才的這個鍵值對給刪除掉.


如果在買票服務器1操作數據庫的過程中,買票服務器2也想買票,也會嘗試給Redis上寫?個鍵值對,key 同樣是?次.但是此時設置的時候發現該?次的key已經存在了,則認為已經有其他服務器正在持有鎖,此時服務器2就需要等待或者暫時放棄.

但是上述?案并不完整.

3)引?過期時間

當服務器1加鎖之后,開始處理買票的過程中,如果服務器1意外宕機了,就會導致解鎖操作(刪除該
key) 不能執?.就可能引起其他服務器始終?法獲取到鎖的情況.
為了解決這個問題,可以在設置key的同時引?過期時間.即這個鎖最多持有多久,就應該被釋放.

注意!此處的過期時間只能使??個命令的?式設置.

如果分開多個操作,?如setnx之后,再來?個單獨的expire,由于Redis的多個指令之間不存在關
聯,并且即使使?了事務也不能保證這兩個操作都?定成功,因此就可能出現setnx成功,但是expire
失敗的情況.
此時仍然會出現?法正確釋放鎖的問題.

4)引?校驗id

對于Redis中寫?的加鎖鍵值對,其他的節點也是可以刪除的.

?????????如服務器1寫??個"001":1這樣的鍵值對,服務器2是完全可以把"001"給刪除掉的.
????????當然,服務器2不會進?這樣的"惡意刪除"操作,不過不能保證因為?些bug導致服務器2把鎖誤刪除.

為了解決上述問題,我們可以引??個校驗id.

?如可以把設置的鍵值對的值,不再是簡單的設為?個1,?是設成服務器的編號.形如"001":"服務器1".


這樣就可以在刪除key(解鎖)的時候,先校驗當前刪除key的服務器是否是當初加鎖的服務器,如果是,才能真正刪除;不是,則不能刪除.

邏輯?偽代碼描述如下:

但是很明顯,解鎖邏輯是兩步操作"get"和"del",這樣做并?是原?的.

5)引?lua

為了使解鎖操作原?,可以使?Redis的Lua腳本功能.

使?Lua腳本完成上述解鎖功能:

if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) 
elsereturn 0 
end;

上述代碼可以編寫成?個.lua后綴的?件,由 redis-cli?或者redis-plus-plus?或者 jedis?等客戶端加載,并發送給Redis服務器,由Redis服務器來執?這段邏輯.

?個lua腳本會被Redis服務器以原?的?式來執?.

redis-plus-plus?和 jedis?如何調?lua,咱們此處不做過多介紹.具體api的寫法?家可以??研究.

6)引?watchdog(看?狗)

上述?案仍然存在?個重要問題.當我們設置了key過期時間之后(?如10s),仍然存在?定的可能性,當任務還沒執?完,key就先過期了.這就導致鎖提前失效.

把這個過期時間設置的?夠?,?如30s,是否能解決這個問題呢?很明顯,設置多?時間合適,是??境的.即使設置再?,也不能完全保證就沒有提前失效的情況.
?且如果設置的太?了,萬?對應的服務器掛了,此時其他服務器也不能及時的獲取到鎖.
因此相?于設置?個固定的?時間,不如動態的調整時間更合適.

所謂watchdog,本質上是加鎖的服務器上的?個單獨的線程,通過這個線程來對鎖過期時間進?"續約".
????????注意,這個線程是業務服務器上的,不是Redis服務器的.

這樣就不擔?鎖提前失效的問題了.?且另???,如果該服務器掛了,看?狗線程也就隨之掛了,此時??續約,這個key?然就可以迅速過期,讓其他服務器能夠獲取到鎖了.

7) 引?Redlock算法

實踐中的Redis?般是以集群的?式部署的(?少是主從的形式,?不是單機).那么就可能出現以下?
較極端的?冤種情況:

為了解決這個問題,Redis的作者提出了Redlock算法.

Redlock算法:

????????我們引??組Redis節點.其中每?組Redis節點都包含?個主節點和若?從節點.并且組和組之間存儲的數據都是?致的,相互之間是"備份"關系(?并?是數據集合的?部分,這點有別于Rediscluster).


????????加鎖的時候,按照?定的順序,寫多個master節點.在寫鎖的時候需要設定操作的"超時時間".?如50ms. 即如果setnx操作超過了50ms還沒有成功,就視為加鎖失敗.

如果給某個節點加鎖失敗,就?即再嘗試下?個節點.
當加鎖成功的節點數超過總節點數的?半,才視為加鎖成功.

????????如上圖,?共五個節點,三個加鎖成功,兩個失敗,此時視為加鎖成功.

這樣的話,即使有某些節點掛了,也不影響鎖的正確性.

同理,釋放鎖的時候,也需要把所有節點都進?解鎖操作.(即使是之前超時的節點,也要嘗試解鎖,盡量保證邏輯嚴密).

簡??之,Redlock算法的核?就是,加鎖操作不能只寫給?個Redis節點,?要寫個多個!!分布式系統中任何?個節點都是不可靠的.最終的加鎖成功結論是"少數服從多數的".


由于?個分布式系統不?于?部分節點都同時出現故障,因此這樣的可靠性要?單個節點來說靠譜不少.

六???其他功能

上述描述中我們解釋了基于Redis的分布式鎖的基本實現原理.
上述鎖只是?個簡單的互斥鎖.但是實際上我們在?些特定場景中,還有?些其他特殊的鎖,?如:

  • 可重?鎖
  • 公平鎖
  • 讀寫鎖
  • ......

基于Redis的分布式鎖,也可以實現上述特性.(當然了對應的實現邏輯也會更復雜).

此處我們不做過多討論了.
實際開發中,我們也并不會真的??實現?個分布式鎖.已經有很多現成的庫幫我們封裝好了,我們直接使?即可.

?如Java中的Redisson,C++中的redis-plus-plus.當然,有些??也會有??版本的分布式鎖的實
現.

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/79739.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79739.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79739.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【MySQL】數據表插入數據

個人主頁:Guiat 歸屬專欄:MySQL 文章目錄 1. 插入數據概述1.1 插入數據的重要性1.2 插入數據的基本原則 2. 基本插入語句2.1 INSERT INTO語法2.2 插入多行數據2.3 不指定列名的插入2.4 插入NULL和默認值 3. 高級插入技術3.1 使用子查詢插入數據3.2 IGNOR…

軟考-軟件設計師中級備考 14、刷題 算法

一、考點歸納 1)排序 2、查找 3、復雜度 4、經典問題 0 - 1 背包動態規劃0 - 1 背包問題具有最優子結構性質和重疊子問題性質。通過動態規劃可以利用一個二維數組來記錄子問題的解,避免重復計算,從而高效地求解出背包能裝下的最大價值。分…

【阿里云】阿里云 Ubuntu 服務器無法更新 systemd(Operation not permitted)的解決方法

零、前言 目前正在使用的Ubuntu服務器中,僅阿里云(不止一臺)出現了這個問題,因此我判定是阿里云服務器獨有的問題。如果你的服務器提供商不是阿里云,那么這篇文章可能對你沒有幫助。 如果已經因為升級錯誤導致依賴沖突…

css 點擊后改變樣式

背景: 期望實現效果:鼠標點擊之后,保持選中樣式。 實現思路:在css樣式中,:active 是一種偽類,用于表示用戶當前正在與被選定的元素進行交互。當用戶點擊或按住鼠標時,元素將被激活,此…

采用AI神經網絡降噪算法的語言降噪消回音處理芯片NR2049-P

隨著AI時代來臨.通話設備的環境噪音抑制也進入AI降噪算法時代. AI神經網絡降噪技術是一款革命性的語音處理技術,他突破了傳統單麥克風和雙麥克風降噪的局限性,利用采集的各種日常環境中的噪音樣本進行訓練學習.讓降噪算法具有自適應噪聲抑制功能,可以根…

不用聯網不用編程,PLC通過智能網關快速實現HTTP協議JSON格式與MES等系統平臺雙向數據通訊

智能網關IGT-DSER集成了多種PLC的原廠協議,方便實現各種PLC、智能儀表通過HTTP協議與MES等各種系統平臺通訊對接。PLC內不用編寫程序,設備不用停機,通過網關的參數配置軟件(下載地址)配置JSON文件的字段與PLC寄存器地址等參數即可。 …

如何將兩臺虛擬機進行搭橋

將兩臺虛擬機實現網絡互通(“搭橋”)需配置虛擬網絡,以下是基于 VMware Workstation 和 VirtualBox 的詳細操作指南(以 Windows 系統為例,Linux 原理類似): 一、VMware Workstation 配置&#x…

Xianyu AutoAgent,AI閑魚客服機器人

Xianyu AutoAgent是一款專為閑魚平臺開發的智能客服機器人系統,旨在提供全天候的自動化服務。它具備多專家協同決策、智能議價和上下文感知對話等功能,能夠管理輕量級的對話記憶,利用完整的對話歷史為用戶提供更自然的交流體驗。 Xianyu Aut…

鍵盤輸出希臘字符方法

在不同操作系統中,輸出希臘字母的方法有所不同。以下是針對 Windows 和 macOS 系統的詳細方法,以及一些通用技巧: 1.Windows 系統 1.1 使用字符映射表 字符映射表是一個內置工具,可以方便地找到并插入希臘字母。 ? 步驟&#xf…

什么是SparkONYarn模式

1. 什么是 Spark on YARN? Spark on YARN 是 Apache Spark 的一種部署模式,允許 Spark 應用程序在 Hadoop YARN 集群上運行,充分利用 YARN 的資源管理和調度能力。這種模式將 Spark 與 Hadoop 生態深度集成,使企業能夠在同一集群…

【git】clone項目后續,github clone的網絡配置,大型項目git log 輸出txt,切換commit學習,goland遠程,自存檔

git網絡配置,解決git clone github速度奇慢 git config --global http.proxy http://127.0.0.1:7897 git config --global https.proxy http://127.0.0.1:7897git log輸出到文件(便于checkout) 這里有些字符如表情會亂碼,不知道…

Java游戲服務器開發流水賬(3)游戲數據的緩存簡介

簡介 游戲服務器數據緩存是一種在游戲服務器運行過程中,用于臨時存儲經常訪問的數據的技術手段,旨在提高游戲性能、降低數據庫負載以及優化玩家體驗。游戲開發中數據的緩存可以使用Java自身的內存也可以使用MemCache,Redis,注意M…

STL?vector!!!

一、前言 之前我們借助手撕string加深了類和對象相關知識,今天我們將一起手撕一個vector,繼續深化類和對象、動態內存管理、模板的相關知識 二、vector相關的前置知識 1、什么是vector? vector是一個STL庫中提供的類模板,它是存儲…

C++學習之路,從0到精通的征途:繼承

目錄 一.繼承的概念及定義 1.繼承的概念 2.繼承的定義 (1)繼承的定義格式 (2)繼承基類成員訪問方式的變化 二.基類與派生類間的轉換 1.派生類對象賦值給基類的引用/指針 2. 派生類對象直接賦值給基類對象 三.繼承的作用域 四.派生類的默認成員函數 1.構造函數 2.拷…

用vue和go實現登錄加密

前端使用CryptoJS默認加密方法: var pass CryptoJS.AES.encrypt(formData.password, key.value).toString()使用 CryptoJS.AES.encrypt() 時不指定加密模式和參數時,CryptoJS 默認會執行以下操作 var encrypted CryptoJS.AES.encrypt("明文&quo…

React百日學習計劃——Deepseek版

階段一:基礎鞏固(1-20天) 目標:掌握HTML/CSS/JavaScript核心語法和開發環境搭建。 每日學習內容: HTML/CSS(1-10天) 標簽語義化、盒模型、Flex布局、Grid布局、響應式設計(媒體查詢…

WPF中如何自定義控件

WPF自定義控件簡化版:賬戶菜單按鈕(AccountButton) 我們以**“賬戶菜單按鈕”為例,用更清晰的架構實現一個支持標題顯示、漸變背景、選中狀態高亮**的自定義控件。以下是分步拆解: 一、控件核心功能 我們要做一個類似…

Deepseek+Xmind:秒速生成思維導圖與流程圖

deepseekxmind,快速生成思維導圖和流程圖 文章目錄 思維導圖deepseek筆記本 txt文件xmind 流程圖deepseekdraw.io 思維導圖 deepseek 筆記本 txt文件 將deep seek的東西復制到文本文件中,然后將txt文件拓展名改成md xmind 新建思維導圖----左上角三…

基于javaweb的SpringBoot愛游旅行平臺設計和實現(源碼+文檔+部署講解)

技術范圍:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容:免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論文…

服務器機架的功能和重要性

服務器已經成為各個行業必不可少的網絡設備,而服務器機架則是數據中心和IT基礎設施中不可或缺的重要組成部分,服務器機架能夠為服務器和其他網絡設備提供物理支撐,同時還可以提供設備維護和管理等多種功能,本文就來介紹一下服務器…