這篇文章帶大家聊聊Redis中的鎖,介紹一下為什麼要用鎖,真的需要Redlock(redis分散式鎖)嗎,希望對大家有幫助!
為什麼要用鎖
我待過的k12教育公司,我們當時有個業務場景是這樣的。業務這邊要給學生排課,偶爾會回饋學生的課時明明充足的但是卻提示課時不足,等再刷新一遍頁面卻發現學生的課時已經不夠了。更可怕的是,偶爾會有學生的課時被扣成負數(公司被白嫖課時)。 【相關推薦:Redis影片教學】
再例如下面這個範例
上面的這兩個問題都是並發給我們的業務帶來的問題。解決這個問題的核心就是,同一時間只能允許有一個請求來對這些敏感(重要)的資料進行讀寫操作。所以這個時候就要使用到分散式鎖來限製程式的並發執行。
setnx有哪些問題
我們先來看看用Redis如何實作分散式鎖,想必大家都很熟悉。例如針對我文章開頭講的學生排課的問題我們就可以這樣加鎖
#這就是我們常規使用setnx來實現鎖的方式。
現在我們假設有這樣一個場景。 A請求拿到鎖到了第2步給學生排課的時候程序掛了,沒有釋放鎖。那麼這個鎖就成了死鎖,下一個操作同一個學生的請求永遠就拿不到鎖,那麼這個學生就沒辦法被排課了。這個時候都需要手動去把鎖釋放掉。
為了解決死鎖的問題,我們給鎖加一個過期時間。
加上過期時間之後,如果A請求沒有主動釋放鎖,在鎖定過期之後也會主動釋放,這樣B請求一樣可以取得鎖定處理業務邏輯。但是如果在加過期時間的時候也就是在第1步和第2步之間程式崩潰。那還是會出現死鎖的問題。這個問題的根源就在於setnx和expire這兩個指令不是原子指令。所以如果setnx和expire能夠要不是全部執行要嘛一個都不執行那該有多好。
為此在Redis2.8之前社區湧現了一大批擴充包來解決這個問題。官方為了治理該亂象,在2.8版本中加入了set指令的擴充參數使得setnx和expire指令可以一起執行,所以現在我們使用分散式鎖定應該是這樣了
這樣看起來已經很完美了,已經達成了我們的期望「setnx和expire能夠要麼全部執行要麼一個都不執行那該多好」。我們再假設現在有以下場景:
A請求現在取得到了鎖,鎖的超時時間設定的是5秒。到了第2步驟執行業務邏輯,結果因為某些原因5秒之後業務邏輯還沒執行完,此時鎖由於逾時自動釋放了。這時候B請求也來了,拿到鎖之後開始執行業務邏輯。 A請求這個時候業務邏輯執行完了,開始執行第三步,釋放了鎖。而這個時候鎖是B請求拿到的,結果被A請求釋放了。那麼C請求就可以拿到鎖了。這時候B請求和C請求就會導致並發問題了。所以可以從這個例子看出來,在分散式鎖中過期時間的設定非常重要,如果設定的時間小於這個介面的回應時間那麼仍然會產生並發問題。所以我們可以參考介面回應時長的監控來設定鎖的過期時間。
Redlock
我們上述的方案都是基於單點的Redis的實作方式。單點的Redis實現分散式鎖基本上可以滿足95%的業務場景。剩下的5%就是對資料一致性要求極為嚴苛並且對於鎖丟失的0容忍的業務場景。這時候就得考慮Redlock了。至於單點的Redis即使透過sentinel保證高可用,如果這個master節點因為某些原因發生了主從切換,如果資料主從資料同步不及時那麼勢必會有資料遺失,那麼就會出現鎖定遺失的情況。
假設存在多個Redis實例,這些節點是完全獨立的,不需要使用複製或任何協調資料的系統,我們假設有5個Redis master節點,客戶端為了取到鎖,步驟將會變成這樣:
以毫秒為單位取得目前的伺服器時間
嘗試使用相同的key和隨機值來取得鎖,客戶端對每一個機器取得鎖時都應該有一個超時時間,例如鎖的過期時間為10s,那麼取得單一節點鎖的超時時間就應該是5到50毫秒左右,他這樣做的目的是為了確保客戶端與故障的機器連接不耗費多餘的時間!超時間時間內未取得資料就放棄該節點,從而去下一個Redis節點取得。
取得完成後,取得目前時間減去步驟一取得的時間,當且僅當客戶端從半數以上(這裡是3個節點)的Redis節點取得到鎖且取得鎖的時間小於鎖額逾時時間,則證明該鎖生效!
如果取到了鎖,key的真正有效時間等於有效時間減去取得鎖所使用的時間(步驟3計算的結果)。
如果取得鎖的機器不滿足半數以上,或者鎖的逾時時間計算完畢後為負數等異常操作,則係統會嘗試解鎖所有實例,即便某些Redis實例根本就沒有加鎖成功,防止某些節點取得到鎖定但是客戶端沒有得到回應而導致接下來的一段時間不能被重新取得鎖定
所以我們看出,redlock其實是比單點Redis看起來更可靠的鎖。
如果你跟我一樣是Node.js程式設計師那麼剛好有第三方函式庫redlock直接使用。
我們真的需要redlock嗎
關於redlock其實也有另外一種聲音,Martin Kleppmann(劍橋大學的研究員,從事資料庫、分散式系統與資訊安全交叉領域的TRVE DATA專案)寫過一篇blog#發表了關於對redlock的一些看法,有興趣的可以看看。 Redis作者Salvatore也對這篇文章的疑問做出了一些回應,還挺有意思的。作者的blog主要的觀點如下:
分散式鎖定的用途無非兩種:
- 效率:使用鎖定可以避免不必要地做同樣的工作兩次(例如一些昂貴的計算)。如果鎖定失敗並且兩個節點最終完成相同的工作,結果是成本略有增加(您最終向AWS 支付的費用比其他情況多5 美分)或帶來輕微的不便(例如,用戶最終兩次收到相同的電子郵件通知)。
- 正確性:使用鎖定可以防止並發進程相互幹擾並破壞系統狀態。如果鎖定失敗並且兩個節點同時處理相同數據,則結果是文件損壞、數據丟失、永久性不一致、給患者服用的藥物劑量錯誤或其他一些非常嚴重的問題。
如果是為了效率,則根本沒有必要承擔Redlock 的成本和複雜性,鎖定遺失導致多發幾次郵件和運行5 個Redis 伺服器的成本相比,最好只使用單一Redis實例。如果你使用的是單一 Redis 實例,Redis 節點突然斷電或崩潰,或出現其他問題,這個時候當然會遺失鎖。但是如果你只是將鎖用作效率優化,而且這種崩潰不會經常發生,那就沒什麼大不了的。這種「沒什麼大不了」的場景是 也剛好是Redis優秀的地方。至少如果依賴單一 Redis 實例,那麼查看系統的每個人都能夠更方便的定位問題。
如果是為了正確性,那麼嚴格來講,redlock根本不具有強一致的嚴格性。舉了一些例子
時序和系統時鐘做出了危險的假設,對每台伺服器的時脈強烈依賴。因為有系統有GC的存在,做GC的時整個伺服器是夯住的,時間也就停滯了,所以我們不能夠對時鐘有強烈依賴。
沒有令牌。客戶端每次取得鎖的時候服務端沒有下發令牌,服務端應該校驗每次操作的時候客戶端的令牌要與服務端目前的令牌一致才難操作鎖。
作者主要就是以上這些個觀點,如果有興趣的還是推薦去看看原文吧。
更多程式相關知識,請造訪:程式設計入門! !
以上是淺析Redis中的鎖,聊聊Redlock(redis分散式鎖)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Redis脫穎而出是因為其高速、多功能性和豐富的數據結構。 1)Redis支持字符串、列表、集合、散列和有序集合等數據結構。 2)它通過內存存儲數據,支持RDB和AOF持久化。 3)從Redis6.0開始引入多線程處理I/O操作,提升了高並發場景下的性能。

RedisisclassifiedasaNoSQLdatabasebecauseitusesakey-valuedatamodelinsteadofthetraditionalrelationaldatabasemodel.Itoffersspeedandflexibility,makingitidealforreal-timeapplicationsandcaching,butitmaynotbesuitableforscenariosrequiringstrictdataintegrityo

Redis通過緩存數據、實現分佈式鎖和數據持久化來提升應用性能和可擴展性。 1)緩存數據:使用Redis緩存頻繁訪問的數據,提高數據訪問速度。 2)分佈式鎖:利用Redis實現分佈式鎖,確保在分佈式環境中操作的安全性。 3)數據持久化:通過RDB和AOF機制保證數據安全性,防止數據丟失。

Redis的數據模型和結構包括五種主要類型:1.字符串(String):用於存儲文本或二進制數據,支持原子操作。 2.列表(List):有序元素集合,適合隊列和堆棧。 3.集合(Set):無序唯一元素集合,支持集合運算。 4.有序集合(SortedSet):帶分數的唯一元素集合,適用於排行榜。 5.哈希表(Hash):鍵值對集合,適合存儲對象。

Redis的數據庫方法包括內存數據庫和鍵值存儲。 1)Redis將數據存儲在內存中,讀寫速度快。 2)它使用鍵值對存儲數據,支持複雜數據結構,如列表、集合、哈希表和有序集合,適用於緩存和NoSQL數據庫。

Redis是一個強大的數據庫解決方案,因為它提供了極速性能、豐富的數據結構、高可用性和擴展性、持久化能力以及廣泛的生態系統支持。 1)極速性能:Redis的數據存儲在內存中,讀寫速度極快,適合高並發和低延遲應用。 2)豐富的數據結構:支持多種數據類型,如列表、集合等,適用於多種場景。 3)高可用性和擴展性:支持主從復制和集群模式,實現高可用性和水平擴展。 4)持久化和數據安全:通過RDB和AOF兩種方式實現數據持久化,確保數據的完整性和可靠性。 5)廣泛的生態系統和社區支持:擁有龐大的生態系統和活躍社區,

Redis的關鍵特性包括速度、靈活性和豐富的數據結構支持。 1)速度:Redis作為內存數據庫,讀寫操作幾乎瞬時,適用於緩存和會話管理。 2)靈活性:支持多種數據結構,如字符串、列表、集合等,適用於復雜數據處理。 3)數據結構支持:提供字符串、列表、集合、哈希表等,適合不同業務需求。

Redis的核心功能是高性能的內存數據存儲和處理系統。 1)高速數據訪問:Redis將數據存儲在內存中,提供微秒級別的讀寫速度。 2)豐富的數據結構:支持字符串、列表、集合等,適應多種應用場景。 3)持久化:通過RDB和AOF方式將數據持久化到磁盤。 4)發布訂閱:可用於消息隊列或實時通信系統。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境