日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Redis分布式鎖的原理是什么?如何續(xù)期?

redis如何防止并發(fā)?

Redis是當(dāng)前炙手可熱的NoSQL數(shù)據(jù)庫,幾乎已經(jīng)成為高并發(fā)、高可用系統(tǒng)的標(biāo)配了。對(duì)Redis響應(yīng)快的認(rèn)知不能僅僅停留在基于內(nèi)存和單線程的層面。

創(chuàng)新互聯(lián)公司是專業(yè)的固始網(wǎng)站建設(shè)公司,固始接單;提供網(wǎng)站設(shè)計(jì)、做網(wǎng)站,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行固始網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!

在一些對(duì)高并發(fā)請(qǐng)求有限制的系統(tǒng)或者功能里,比如說秒殺活動(dòng),或者一些網(wǎng)站返回的當(dāng)前用戶過多,請(qǐng)稍后嘗試。這些都是通過對(duì)同一時(shí)刻請(qǐng)求數(shù)量進(jìn)行了限制,一般用作對(duì)后臺(tái)系統(tǒng)的保護(hù),防止系統(tǒng)因?yàn)檫^大的流量沖擊而崩潰。對(duì)于系統(tǒng)崩潰帶來的后果,顯然還是拒絕一部分請(qǐng)求更能被維護(hù)者所接受。

而在各種限流中,除了系統(tǒng)自身設(shè)計(jì)的帶鎖機(jī)制的計(jì)數(shù)器外,利用Redis實(shí)現(xiàn)顯然是一種既高效安全又便捷方便的方式。

客戶端加鎖(ReentrantLock或synchronized)

但此方式只限于單機(jī)加鎖,無法解決分布式系統(tǒng)的并發(fā)競(jìng)爭(zhēng)問題。

樂觀鎖(redis 的命令 watch)
當(dāng)執(zhí)行多鍵值事務(wù)操作時(shí),Redis 不僅要求這些鍵值需要落在同一個(gè) Redis 實(shí)例上,還要求落在同一個(gè) slot 上,所以 redis 的事務(wù)比較雞肋,不過可以想辦法遵循 redis 內(nèi)部的分片算法把設(shè)計(jì)到的所有 key 分到同一個(gè) slot。

redis 的 setnx 實(shí)現(xiàn)分布式鎖
要設(shè)置超時(shí)時(shí)間,防止搶占到鎖的客戶端因失敗、崩潰或其他原因沒有辦法釋放鎖而造成死鎖。

如有不同觀點(diǎn),歡迎發(fā)表評(píng)論。如果喜歡我的回答,歡迎“點(diǎn)贊、分享”。

1. 問題描述

并發(fā)競(jìng)爭(zhēng)key這個(gè)問題簡(jiǎn)單講就是:

同時(shí)有多個(gè)客戶端去set一個(gè)key。

示例場(chǎng)景 1

例如有多個(gè)請(qǐng)求一起去對(duì)某個(gè)商品減庫存,通常操作流程是:

假設(shè)當(dāng)前庫存值為 20,現(xiàn)在有2個(gè)連接都要減 5,結(jié)果庫存值應(yīng)該是 10 才對(duì),但存在下面這種情況:

示例場(chǎng)景 2

比如有3個(gè)請(qǐng)求有序的修改某個(gè)key,按正常順序的話,數(shù)據(jù)版本應(yīng)該是 1->2->3,最后應(yīng)該是 3。

但如果第二個(gè)請(qǐng)求由于網(wǎng)絡(luò)原因遲到了,數(shù)據(jù)版本就變?yōu)榱?1->3->2,最后值為 2,出問題了。

redis 本身是單進(jìn)程、單線程的模型,就是說一個(gè)時(shí)刻就只能有一個(gè)東東在執(zhí)行,不管是多少個(gè)命令,只能是串行執(zhí)行,因此從這個(gè)意義上保證了單個(gè)命令執(zhí)行的多線程(多個(gè)客戶端操作)的安全,也就是不管有多少個(gè)客戶端在發(fā)請(qǐng)求,redis每次只能執(zhí)行一個(gè)客戶端的命令,不存在多線程。

但是redis對(duì)于多個(gè)客戶端的多個(gè)命令,并不能保證其線程安全性,比如有一個(gè)值x=1;如果ClientA 獲取x的值,x=x+1,然后再設(shè)置回去;在此期間,有一個(gè)ClientB做同樣的操作;如果ClientA、ClientB的操作被串行了,那么x=3;但是多個(gè)命令之間不能保證(除非是增加了所謂的鎖之類的東東),從而x的值就不一定是3了,這個(gè)時(shí)候就存在了并發(fā)操作的問題。

當(dāng)然redis也考慮到了相關(guān)的情況,提供了incr之類的原子操作命令,保證了多線程并發(fā)操作的安全性;

對(duì)于同一個(gè)客戶的多次點(diǎn)擊操作,如果不做區(qū)分,可能就存在問題,比如支付寶的種樹澆水這個(gè)操作,如果不做控制,一個(gè)用戶快速的多次點(diǎn)擊,可能就會(huì)超過3次(支付寶限制一天只能幫某個(gè)好友澆水3次),這個(gè)時(shí)候其實(shí)有簡(jiǎn)單的解決方法:比如每次澆水有一個(gè)澆水ID,第1、2、3次都有一個(gè)不同的ID,從第4次開始的操作其ID還是設(shè)置為3(由客戶端來限制),那么后臺(tái)只要判斷ID是否重復(fù),就可以做過濾; 同樣的問題在第三方API對(duì)接的時(shí)候也存在(比如調(diào)用支付寶付款,有時(shí)候網(wǎng)絡(luò)不好,是否會(huì)存在多次付費(fèi)問題?),此時(shí)我想每個(gè)支付的請(qǐng)求也帶了一個(gè)唯一的ID,保證了支付的唯一性(當(dāng)然可能還會(huì)有對(duì)用戶名、支付款項(xiàng)的驗(yàn)證--銀行支付的時(shí)候往往會(huì)提醒你,你支付了一筆同樣的款項(xiàng),需要確認(rèn)--具體的場(chǎng)景是你需要支付某人1000塊,你分成500、500兩筆,此時(shí)網(wǎng)銀操作是會(huì)提醒你的);

因此對(duì)于相同的2個(gè)請(qǐng)求,如果是一種冪等的操作--比如都是get某個(gè)值(不會(huì)變的),那么其實(shí)處不處理看策略,至少不會(huì)造成不一致;對(duì)于支付這樣的行為,肯定需要做判斷確定是同一個(gè)請(qǐng)求,對(duì)另外一個(gè)請(qǐng)求做過濾。

對(duì)于很多系統(tǒng)而言,都有集群處理。在集群中使用quartz或者task處理任務(wù)的時(shí)候,一般有三種選擇:

1. 多實(shí)例順序執(zhí)行

2. 單實(shí)例執(zhí)行

3. 多實(shí)例并行執(zhí)行

創(chuàng)保目前考慮的是1情況。

redis對(duì)于并發(fā)較小的情況下,進(jìn)行鎖控制,效果是較為理想的。目前創(chuàng)保只有八臺(tái)實(shí)例,適用于該方案。

1. 首先,redis提供了一個(gè)setnx方法,該方法執(zhí)行后會(huì)返回key值在設(shè)置之前是否存在。

這是進(jìn)行并發(fā)控制的基礎(chǔ),但并不夠。

2. 在利用 setnx 進(jìn)行 key 值設(shè)定后,如果instance發(fā)生異常(不僅僅是exception)會(huì)導(dǎo)致該鎖無法正常釋放。

所以,我們需要為鎖設(shè)置一個(gè)失效時(shí)間,即expire命令。

Redis分布式鎖的原理是什么?如何續(xù)期?

在傳統(tǒng)單體應(yīng)用單機(jī)部署的情況下,并發(fā)問題可以通過使用Java并發(fā)相關(guān)的鎖如synchronized,但是當(dāng)規(guī)模上升到分布式集群的情況下,要控制共享資源訪問,就需要通過分布式鎖來實(shí)現(xiàn)。常見的分布式鎖方案如數(shù)據(jù)庫樂觀鎖,Redis鎖,zk鎖等。

Redis分布式鎖可以有多種方式實(shí)現(xiàn)但是其核心就是通過以下三個(gè)Redis命令組合實(shí)現(xiàn)。

上面為Redis的一個(gè)最簡(jiǎn)單的鎖實(shí)現(xiàn)原理,實(shí)際中還需要考慮更多具體的情況作出相應(yīng)的調(diào)整。如

實(shí)際開發(fā)環(huán)境中不確定的因素有很多,需要慢慢地去調(diào)整實(shí)踐達(dá)到理想狀態(tài),可以考慮使用redisson框架來實(shí)現(xiàn)。

這個(gè)情況比較獨(dú)特,出現(xiàn)這個(gè)問題的根本原因在于鎖失效的時(shí)間小于業(yè)務(wù)處理的時(shí)間導(dǎo)致業(yè)務(wù)還沒處理完畢鎖就釋放了。那么解決方案是合理地結(jié)合業(yè)務(wù)去設(shè)置鎖失效的時(shí)間。

但是也有更好的方案就如前文提到的redisson,其中的可重入鎖概念。


默認(rèn)情況下,加鎖的時(shí)間是30秒.如果加鎖的業(yè)務(wù)沒有執(zhí)行完,那么到 30-10 = 20秒的時(shí)候,就會(huì)進(jìn)行一次續(xù)期,把鎖重置成30秒。

分布式鎖的需求產(chǎn)生

分布式鎖的需求是伴隨著應(yīng)用分布式部署而來的,在單體應(yīng)用,且只部署一臺(tái)服務(wù)器的情況下,通過java的同步鎖即可實(shí)現(xiàn)。同步鎖,即是一個(gè)原子性的操作。

那么當(dāng)應(yīng)用進(jìn)行了分布式部署,應(yīng)用有多個(gè)服務(wù),這個(gè)時(shí)候應(yīng)用服務(wù)端就沒有一個(gè)可提供原子性操作的地方了,Redis性能高,且是單線程,因此可提供一個(gè)原子性操作的地方,利用它,就可以實(shí)現(xiàn)分布式鎖。

用場(chǎng)景說話,使用Redis分布式鎖的場(chǎng)景如下圖所示:

如下圖所示,隨后會(huì)根據(jù)場(chǎng)景說明分布式鎖及續(xù)期相關(guān)問題的來龍去脈。

  1. 圖中序號(hào)1:進(jìn)來一個(gè)請(qǐng)求,這個(gè)請(qǐng)求要求我們保存一個(gè)“訂單A”;
  2. 圖中序號(hào)2:2.1 步,請(qǐng)求進(jìn)來,首先去嘗試設(shè)置一個(gè)Redis 值,他的鍵就是訂單號(hào)“訂單A”,如果嘗試成功,則代表我這個(gè)線程是第一次設(shè)置,相當(dāng)于我拿到了這個(gè)鎖;如果嘗試失敗,那么,可以拋出異?;蛘叩却欢螘r(shí)候后再次重試,這里可以根據(jù)業(yè)務(wù)場(chǎng)景的不同采取不同的策略。這里的關(guān)鍵是在Redis中的操作是單線程的,因此該操作是原子性的。2.2步,為了防止應(yīng)用服務(wù)意外中斷,Redis中的數(shù)據(jù)一直存活,消耗資源,需要設(shè)置一個(gè)超時(shí)時(shí)間。(如果為了嚴(yán)謹(jǐn),可以將2.1, 2.2 兩步封裝成一個(gè)lua腳本部署在Redis服務(wù)器上)
  3. 圖中序號(hào)3:情況A,這個(gè)時(shí)候是當(dāng)Redis的key還未失效,程序就已經(jīng)執(zhí)行完成,且刪除了Redis中的數(shù)據(jù),一切正常;情況B:就是需要續(xù)期的場(chǎng)景,如果要避免這個(gè)場(chǎng)景的出現(xiàn),可以將Redis key的失效時(shí)間設(shè)置長(zhǎng)一點(diǎn),可以應(yīng)對(duì)大多數(shù)業(yè)務(wù)。如果要徹底解決,可以在應(yīng)用端添加一個(gè)Redis鎖的注冊(cè)中心,然后起一個(gè)監(jiān)聽線程去監(jiān)聽這個(gè)注冊(cè)中心,發(fā)現(xiàn)有鎖還在被持有,但是Redis 已經(jīng)快過期了,則修改相應(yīng)key的失效時(shí)間,進(jìn)行續(xù)期。

到此,以上就是小編對(duì)于redis 并發(fā)鎖的問題就介紹到這了,希望這2點(diǎn)解答對(duì)大家有用。


分享文章:Redis分布式鎖的原理是什么?如何續(xù)期?
本文網(wǎng)址:http://www.dlmjj.cn/article/dhijjcj.html