溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何通過Redis實(shí)現(xiàn)分布式鎖

發(fā)布時(shí)間:2021-12-22 16:41:05 來源:億速云 閱讀:193 作者:iii 欄目:編程語言

這篇文章主要介紹“如何通過Redis實(shí)現(xiàn)分布式鎖”,在日常操作中,相信很多人在如何通過Redis實(shí)現(xiàn)分布式鎖問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對(duì)大家解答”如何通過Redis實(shí)現(xiàn)分布式鎖”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

常用的 SQL 數(shù)據(jù)庫的數(shù)據(jù)都是存在磁盤中的,雖然在數(shù)據(jù)庫底層也做了對(duì)應(yīng)的緩存來減少數(shù)據(jù)庫的 IO 壓力。
由于數(shù)據(jù)庫的緩存一般是針對(duì)查詢的內(nèi)容,而且粒度也比較小,一般只有表中的數(shù)據(jù)沒有發(fā)生變動(dòng)的時(shí)候,數(shù)據(jù)庫的緩存才會(huì)產(chǎn)生作用。但這并不能減少業(yè)務(wù)邏輯對(duì)數(shù)據(jù)庫的增刪改操作的 IO 壓力,因此緩存技術(shù)應(yīng)運(yùn)而生,該技術(shù)實(shí)現(xiàn)了對(duì)熱點(diǎn)數(shù)據(jù)的高速緩存,可以大大緩解后端數(shù)據(jù)庫的壓力。

1、主流應(yīng)用架構(gòu):

客戶端在對(duì)數(shù)據(jù)庫發(fā)起請(qǐng)求時(shí),先到緩存層查看是否有所需的數(shù)據(jù),如果緩存層存有客戶端所需的數(shù)據(jù),則直接從緩存層返回,否則進(jìn)行穿透查詢,對(duì)數(shù)據(jù)庫進(jìn)行查詢。如果在數(shù)據(jù)庫中查詢到該數(shù)據(jù),則將該數(shù)據(jù)回寫到緩存層,以便下次客戶端再次查詢能夠直接從緩存層獲取數(shù)據(jù)。

2、為什么 Redis 能這么快

Redis 的效率很高,官方給出的數(shù)據(jù)是 100000+QPS,這是因?yàn)椋篟edis 完全基于內(nèi)存,絕大部分請(qǐng)求是純粹的內(nèi)存操作,執(zhí)行效率高。Redis 使用單進(jìn)程單線程模型的(K,V)數(shù)據(jù)庫,將數(shù)據(jù)存儲(chǔ)在內(nèi)存中,存取均不會(huì)受到硬盤 IO 的限制,因此其執(zhí)行速度極快。另外單線程也能處理高并發(fā)請(qǐng)求,還可以避免頻繁上下文切換和鎖的競爭,如果想要多核運(yùn)行也可以啟動(dòng)多個(gè)實(shí)例。

數(shù)據(jù)結(jié)構(gòu)簡單,對(duì)數(shù)據(jù)操作也簡單,Redis 不使用表,不會(huì)強(qiáng)制用戶對(duì)各個(gè)關(guān)系進(jìn)行關(guān)聯(lián),不會(huì)有復(fù)雜的關(guān)系限制,其存儲(chǔ)結(jié)構(gòu)就是鍵值對(duì),類似于 HashMap,HashMap 最大的優(yōu)點(diǎn)就是存取的時(shí)間復(fù)雜度為 O(1)。
Redis 使用多路 I/O 復(fù)用模型,為非阻塞 IO。注:Redis 采用的 I/O 多路復(fù)用函數(shù):epoll/kqueue/evport/select。

選用策略:

因地制宜,優(yōu)先選擇時(shí)間復(fù)雜度為 O(1) 的 I/O 多路復(fù)用函數(shù)作為底層實(shí)現(xiàn)。由于 Select 要遍歷每一個(gè) IO,所以其時(shí)間復(fù)雜度為 O(n),通常被作為保底方案。基于 React 設(shè)計(jì)模式監(jiān)聽 I/O 事件。

3、Redis 的數(shù)據(jù)類型

String:最基本的數(shù)據(jù)類型,其值最大可存儲(chǔ) 512M,二進(jìn)制安全(Redis 的 String 可以包含任何二進(jìn)制數(shù)據(jù),包含 jpg 對(duì)象等)。注:如果重復(fù)寫入 key 相同的鍵值對(duì),后寫入的會(huì)將之前寫入的覆蓋。

Hash:String 元素組成的字典,適用于存儲(chǔ)對(duì)象。

List:列表,按照 String 元素插入順序排序。其順序?yàn)楹筮M(jìn)先出。由于其具有棧的特性,所以可以實(shí)現(xiàn)如“最新消息排行榜”這類的功能。

Set:String 元素組成的無序集合,通過哈希表實(shí)現(xiàn)(增刪改查時(shí)間復(fù)雜度為 O(1)),不允許重復(fù)。另外,當(dāng)我們使用 Smembers 遍歷 Set 中的元素時(shí),其順序也是不確定的,是通過 Hash 運(yùn)算過后的結(jié)果。Redis 還對(duì)集合提供了求交集、并集、差集等操作,可以實(shí)現(xiàn)如同共同關(guān)注,共同好友等功能。

Sorted Set:通過分?jǐn)?shù)來為集合中的成員進(jìn)行從小到大的排序。

更高級(jí)的Redis類型:用于計(jì)數(shù)的HyperLogLog、用于支持存儲(chǔ)地理位置信息的 Geo。

4、如何通過 Redis 實(shí)現(xiàn)分布式鎖

分布式鎖:分布式鎖是控制分布式系統(tǒng)之間共同訪問共享資源的一種鎖的實(shí)現(xiàn)。如果一個(gè)系統(tǒng),或者不同系統(tǒng)的不同主機(jī)之間共享某個(gè)資源時(shí),往往需要互斥,來排除干擾,滿足數(shù)據(jù)一致性。

分布式鎖需要解決的問題如下:

互斥性:任意時(shí)刻只有一個(gè)客戶端獲取到鎖,不能有兩個(gè)客戶端同時(shí)獲取到鎖。

安全性:鎖只能被持有該鎖的客戶端刪除,不能由其他客戶端刪除。

死鎖:獲取鎖的客戶端因?yàn)槟承┰蚨礄C(jī)繼而無法釋放鎖,其他客戶端再也無法獲取鎖而導(dǎo)致死鎖,此時(shí)需要有特殊機(jī)制來避免死鎖。

容錯(cuò):當(dāng)各個(gè)節(jié)點(diǎn),如某個(gè) Redis 節(jié)點(diǎn)宕機(jī)的時(shí)候,客戶端仍然能夠獲取鎖或釋放鎖。

5、如何實(shí)現(xiàn)異步隊(duì)列

(1)使用 Redis 中的 List 作為隊(duì)列

使用上文所說的 Redis 的數(shù)據(jù)結(jié)構(gòu)中的 List 作為隊(duì)列 Rpush 生產(chǎn)消息,LPOP 消費(fèi)消息。此時(shí)我們可以看到,該隊(duì)列是使用 Rpush 生產(chǎn)隊(duì)列,使用 LPOP 消費(fèi)隊(duì)列。在這個(gè)生產(chǎn)者-消費(fèi)者隊(duì)列里,當(dāng) LPOP 沒有消息時(shí),證明該隊(duì)列中沒有元素,并且生產(chǎn)者還沒有來得及生產(chǎn)新的數(shù)據(jù)。

缺點(diǎn):LPOP 不會(huì)等待隊(duì)列中有值之后再消費(fèi),而是直接進(jìn)行消費(fèi)。

彌補(bǔ):可以通過在應(yīng)用層引入 Sleep 機(jī)制去調(diào)用 LPOP 重試。

(2)使用 BLPOP key [key…] timeout

BLPOP key [key …] timeout:阻塞直到隊(duì)列有消息或者超時(shí)。

缺點(diǎn):按照此種方法,我們生產(chǎn)后的數(shù)據(jù)只能提供給各個(gè)單一消費(fèi)者消費(fèi)。能否實(shí)現(xiàn)生產(chǎn)一次就能讓多個(gè)消費(fèi)者消費(fèi)呢?

(3)Pub/Sub:主題訂閱者模式

發(fā)送者(Pub)發(fā)送消息,訂閱者(Sub)接收消息。訂閱者可以訂閱任意數(shù)量的頻道。Pub/Sub模式的缺點(diǎn):消息的發(fā)布是無狀態(tài)的,無法保證可達(dá)。對(duì)于發(fā)布者來說,消息是“即發(fā)即失”的。此時(shí)如果某個(gè)消費(fèi)者在生產(chǎn)者發(fā)布消息時(shí)下線,重新上線之后,是無法接收該消息的,要解決該問題需要使用專業(yè)的消息隊(duì)列,如 Kafka…此處不再贅述。

6、Redis 持久化

(1)什么是持久化?

持久化,即將數(shù)據(jù)持久存儲(chǔ),而不因斷電或其他各種復(fù)雜外部環(huán)境影響數(shù)據(jù)的完整性。由于 Redis 將數(shù)據(jù)存儲(chǔ)在內(nèi)存而不是磁盤中,所以內(nèi)存一旦斷電,Redis 中存儲(chǔ)的數(shù)據(jù)也隨即消失,這往往是用戶不期望的,所以 Redis 有持久化機(jī)制來保證數(shù)據(jù)的安全性。

(2)Redis 如何做持久化

Redis 目前有兩種持久化方式,即 RDB 和 AOF,RDB 是通過保存某個(gè)時(shí)間點(diǎn)的全量數(shù)據(jù)快照實(shí)現(xiàn)數(shù)據(jù)的持久化,當(dāng)恢復(fù)數(shù)據(jù)時(shí),直接通過 RDB 文件中的快照,將數(shù)據(jù)恢復(fù)。如何從海量數(shù)據(jù)里快速找到所需?

①分片:按照某種規(guī)則去劃分?jǐn)?shù)據(jù),分散存儲(chǔ)在多個(gè)節(jié)點(diǎn)上。通過將數(shù)據(jù)分到多個(gè) Redis 服務(wù)器上,來減輕單個(gè) Redis 服務(wù)器的壓力。

②一致性 Hash 算法:既然要將數(shù)據(jù)進(jìn)行分片,那么通常的做法就是獲取節(jié)點(diǎn)的 Hash 值,然后根據(jù)節(jié)點(diǎn)數(shù)求模。但這樣的方法有明顯的弊端,當(dāng) Redis 節(jié)點(diǎn)數(shù)需要?jiǎng)討B(tài)增加或減少的時(shí)候,會(huì)造成大量的 Key 無法被命中。所以 Redis 中引入了一致性 Hash 算法。該算法對(duì) 2^32 取模,將 Hash 值空間組成虛擬的圓環(huán),整個(gè)圓環(huán)按順時(shí)針方向組織,每個(gè)節(jié)點(diǎn)依次為 0、1、2…2^32-1。

之后將每個(gè)服務(wù)器進(jìn)行 Hash 運(yùn)算,確定服務(wù)器在這個(gè) Hash 環(huán)上的地址,確定了服務(wù)器地址后,對(duì)數(shù)據(jù)使用同樣的 Hash 算法,將數(shù)據(jù)定位到特定的 Redis 服務(wù)器上。如果定位到的地方?jīng)]有 Redis 服務(wù)器實(shí)例,則繼續(xù)順時(shí)針尋找,找到的第一臺(tái)服務(wù)器即該數(shù)據(jù)最終的服務(wù)器位置。

③Hash 環(huán)的數(shù)據(jù)傾斜問題
Hash 環(huán)在服務(wù)器節(jié)點(diǎn)很少的時(shí)候,容易遇到服務(wù)器節(jié)點(diǎn)不均勻的問題,這會(huì)造成數(shù)據(jù)傾斜,數(shù)據(jù)傾斜指的是被緩存的對(duì)象大部分集中在 Redis 集群的其中一臺(tái)或幾臺(tái)服務(wù)器上。一致性 Hash 算法運(yùn)算后的數(shù)據(jù)大部分被存放在 A 節(jié)點(diǎn)上,而 B 節(jié)點(diǎn)只存放了少量的數(shù)據(jù),久而久之 A 節(jié)點(diǎn)將被撐爆。針對(duì)這一問題,可以引入虛擬節(jié)點(diǎn)解決。簡單地說,就是為每一個(gè)服務(wù)器節(jié)點(diǎn)計(jì)算多個(gè) Hash,每個(gè)計(jì)算結(jié)果位置都放置一個(gè)此服務(wù)器節(jié)點(diǎn),稱為虛擬節(jié)點(diǎn),可以在服務(wù)器 IP 或者主機(jī)名后放置一個(gè)編號(hào)實(shí)現(xiàn)。

到此,關(guān)于“如何通過Redis實(shí)現(xiàn)分布式鎖”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI