當前位置:首頁 » 硬碟大全 » 分布式緩存鎖沒有鎖住
擴展閱讀

分布式緩存鎖沒有鎖住

發布時間: 2022-05-19 03:47:29

❶ Redis分布式鎖的原理是什麼如何續期

在傳統單體應用單機部署的情況下,並發問題可以通過使用Java並發相關的鎖如synchronized,但是當規模上升到分布式集群的情況下,要控制共享資源訪問,就需要通過分布式鎖來實現。常見的分布式鎖方案如資料庫樂觀鎖,Redis鎖,zk鎖等。

Redis分布式鎖的原理
Redis分布式鎖可以有多種方式實現但是其核心就是通過以下三個Redis命令組合實現。

SETNX SETNX key val 當且僅當key不存在時,set一個key為val的字元串,返回1;若key存在,則什麼都不做,返回0。

Expire expire key timeout 為key設置一個超時時間,單位為second,超過這個時間鎖會自動釋放,避免死鎖。

Delete delete key 刪除key

核心思想
使用setnx獲取鎖。如果成功取到鎖,則使用expire命令為鎖添加一個超時時間,超過該時間則自動釋放鎖。

獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。

注意
上面為Redis的一個最簡單的鎖實現原理,實際中還需要考慮更多具體的情況作出相應的調整。如

上面的demo中,當集群系統時間不一致時會有問題

當伺服器異常關閉或是重啟,加鎖後沒來得急設置鎖超時時間,如何避免死鎖

實際開發環境中不確定的因素有很多,需要慢慢地去調整實踐達到理想狀態,可以考慮使用redisson框架來實現。
如何續期?
這個情況比較獨特,出現這個問題的根本原因在於鎖失效的時間小於業務處理的時間導致業務還沒處理完畢鎖就釋放了。那麼解決方案是合理地結合業務去設置鎖失效的時間。

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

默認情況下,加鎖的時間是30秒.如果加鎖的業務沒有執行完,那麼到 30-10 = 20秒的時候,就會進行一次續期,把鎖重置成30秒。

以上就是redis鎖的原理及續期的方式,希望我的回答能對你有所幫助。

❷ 什麼是分布式鎖及正確使用redis實現分布式鎖

Redis分布式鎖的安全性問題,在分布式系統專家和Redis的作者 antirez 之間就發生過一場爭論。由於對這個問題一直以來比較關注,所以我前些日子仔細閱讀了與這場爭論相關的資料。這場爭論的大概過程是這樣的:
為了規范各家對基於Redis的分布式鎖的實現,Redis的作者提出了一個更安全的實現,叫做 Redlock 。

❸ 在分布式系統中,怎麼memcache實現分布式鎖,可以實現嗎

您好,很高興為您解答。 在在分布式系統中,實現分布式鎖 用法 要遵循一定條件。 用memcache是沒法實現分布式鎖的,用CAS也是不嚴謹的。paxos演算法可以實現,像zookeeper 如果有疑問可以網路如果沒有問題的話請~~我謝謝

❹ 分布式鎖的三種實現方式

分布式鎖的三種實現方式分別是:基於資料庫實現分布式鎖、基於緩存(Redis等)實現分布式鎖、基於Zookeeper實現分布式鎖。

一、基於資料庫實現分布式鎖

1、悲觀鎖

利用select … where … for update 排他鎖。

注意:其他附加功能與實現一基本一致,這里需要注意的是「where name=lock 」,name欄位必須要走索引,否則會鎖表。有些情況下,比如表不大,mysql優化器會不走這個索引,導致鎖表問題。

2、樂觀鎖

所謂樂觀鎖與前邊最大區別在於基於CAS思想,是不具有互斥性,不會產生鎖等待而消耗資源,操作過程中認為不存在並發沖突,只有update version失敗後才能覺察到,搶購和秒殺就是用了這種實現以防止超賣,通過增加遞增的版本號欄位實現樂觀鎖。

二、基於緩存(Redis等)實現分布式鎖

1、使用命令介紹:

(1)SETNX

SETNX key val:當且僅當key不存在時,set一個key為val的字元串,返回1;若key存在,則什麼都不做,返回0。

(2)expire

expire key timeout:為key設置一個超時時間,單位為second,超過這個時間鎖會自動釋放,避免死鎖。

(3)delete

delete key:刪除key

在使用Redis實現分布式鎖的時候,主要就會使用到這三個命令。

2、實現思想:

(1)獲取鎖的時候,使用setnx加鎖,並使用expire命令為鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值為一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷。

(2)獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。

(3)釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執行delete進行鎖釋放。

三、基於Zookeeper實現分布式鎖

ZooKeeper是一個為分布式應用提供一致性服務的開源組件,它內部是一個分層的文件系統目錄樹結構,規定同一個目錄下只能有一個唯一文件名。

基於ZooKeeper實現分布式鎖的步驟如下:

(1)創建一個目錄mylock。

(2)線程A想獲取鎖就在mylock目錄下創建臨時順序節點。

(3)獲取mylock目錄下所有的子節點,然後獲取比自己小的兄弟節點,如果不存在,則說明當前線程順序號最小,獲得鎖。

(4)線程B獲取所有節點,判斷自己不是最小節點,設置監聽比自己次小的節點。

(5)線程A處理完,刪除自己的節點,線程B監聽到變更事件,判斷自己是不是最小的節點,如果是則獲得鎖。

(4)分布式緩存鎖沒有鎖住擴展閱讀;

一、資料庫分布式鎖實現的缺點:

1、db操作性能較差,並且有鎖表的風險。

2、非阻塞操作失敗後,需要輪詢,佔用cpu資源。

3、長時間不commit或者長時間輪詢,可能會佔用較多連接資源。

二、Redis(緩存)分布式鎖實現的缺點:

1、鎖刪除失敗,過期時間不好控制。

2、非阻塞,操作失敗後,需要輪詢,佔用cpu資源。

三、ZK分布式鎖實現的缺點:

性能不如redis實現,主要原因是寫操作(獲取鎖釋放鎖)都需要在Leader上執行,然後同步到follower。

❺ Redis 分布式鎖有什麼缺陷

Redis 分布式鎖不能解決超時的問題,分布式鎖有一個超時時間,程序的執行如果超出了鎖的超時時間就會出現問題。

❻ 分布式鎖是什麼

什麼是分布式鎖?實現分布式鎖的三種方式

在很多場景中,我們為了保證數據的最終一致性,需要很多的技術方案來支持,比如分布式事務、分布式鎖等。那具體什麼是分布式鎖,分布式鎖應用在哪些業務場景、如何來實現分布式鎖呢?

一 為什麼要使用分布式鎖

我們在開發應用的時候,如果需要對某一個共享變數進行多線程同步訪問的時候,可以使用我們學到的鎖進行處理,並且可以完美的運行,毫無Bug!

注意這是單機應用,後來業務發展,需要做集群,一個應用需要部署到幾台機器上然後做負載均衡,大致如下圖:

六、基於ZooKeeper的實現方式

ZooKeeper是一個為分布式應用提供一致性服務的開源組件,它內部是一個分層的文件系統目錄樹結構,規定同一個目錄下只能有一個唯一文件名。基於ZooKeeper實現分布式鎖的步驟如下:

(1)創建一個目錄mylock;
(2)線程A想獲取鎖就在mylock目錄下創建臨時順序節點;
(3)獲取mylock目錄下所有的子節點,然後獲取比自己小的兄弟節點,如果不存在,則說明當前線程順序號最小,獲得鎖;
(4)線程B獲取所有節點,判斷自己不是最小節點,設置監聽比自己次小的節點;
(5)線程A處理完,刪除自己的節點,線程B監聽到變更事件,判斷自己是不是最小的節點,如果是則獲得鎖。

這里推薦一個Apache的開源庫Curator,它是一個ZooKeeper客戶端,Curator提供的InterProcessMutex是分布式鎖的實現,acquire方法用於獲取鎖,release方法用於釋放鎖。

優點:具備高可用、可重入、阻塞鎖特性,可解決失效死鎖問題。

缺點:因為需要頻繁的創建和刪除節點,性能上不如Redis方式。

七、總結


上面的三種實現方式,沒有在所有場合都是完美的,所以,應根據不同的應用場景選擇最適合的實現方式。

在分布式環境中,對資源進行上鎖有時候是很重要的,比如搶購某一資源,這時候使用分布式鎖就可以很好地控制資源。
當然,在具體使用中,還需要考慮很多因素,比如超時時間的選取,獲取鎖時間的選取對並發量都有很大的影響,上述實現的分布式鎖也只是一種簡單的實現,主要是一種思想。

❼ 大家所推崇的 Redis 分布式鎖,真的可以萬無一失嗎

使用Redis實現分布式鎖最簡單的方案是使用命令SETNX。SETNX(SET if Not eXist)的使用方式為:SETNX key value,只在鍵key不存在的情況下,將鍵key的值設置為value,若鍵key存在,則SETNX不做任何動作。SETNX在設置成功時返回,設置失敗時返回0。當要獲取鎖時,直接使用SETNX獲取鎖,當要釋放鎖時,使用DEL命令刪除掉對應的鍵key即可。
上面這種方案有一個致命問題,就是某個線程在獲取鎖之後由於某些異常因素(比如宕機)而不能正常的執行解鎖操作,那麼這個鎖就永遠釋放不掉了。為此,我們可以為這個鎖加上一個超時時間。第一時間我們會聯想到Redis的EXPIRE命令(EXPIRE key seconds)。但是這里我們不能使用EXPIRE來實現分布式鎖,因為它與SETNX一起是兩個操作,在這兩個操作之間可能會發生異常,從而還是達不到預期的結果

這里我們一眼就可以看出問題來:GET和DEL是兩個分開的操作,在GET執行之後且在DEL執行之前的間隙是可能會發生異常的。如果我們只要保證解鎖的代碼是原子性的就能解決問題了。這里我們引入了一種新的方式,就是Lua腳本,解鎖的時候還是使用DEL命令來解鎖。
修改之後的方案看上去很完美,但實際上還是會有問題。試想一下,某線程A獲取了鎖並且設置了過期時間為10s,然後在執行業務邏輯的時候耗費了15s,此時線程A獲取的鎖早已被Redis的過期機制自動釋放了。在線程A獲取鎖並經過10s之後,改鎖可能已經被其它線程獲取到了。當線程A執行完業務邏輯准備解鎖(DEL key)的時候,有可能刪除掉的是其它線程已經獲取到的鎖,總的來說Redis 分布式鎖不是那麼萬無一失的。

❽ 分布式鎖原理

分布式鎖是控制分布式系統之間同步訪問共享資源的一種方式。原理就是,當我們要實現分布式鎖,最簡單的方式可能就是直接創建一張鎖表,然後通過操作該表中的數據來實現了。

就是要鎖住某個方法或資源時,我們就在該表中增加一條記錄,想要釋放鎖的時候就刪除這條記錄。

在分布式系統中,常常需要協調他們的動作。如果不同的系統或是同一個系統的不同主機之間共享了一個或一組資源,那麼訪問這些資源的時候,往往需要互斥來防止彼此干擾來保證一致性,這個時候,便需要使用到分布式鎖。

當在分布式模型下,數據可能只有一份,此時需要利用鎖的技術控制某一時刻修改數據的進程數。與單機模式下的鎖不同,分布式鎖不僅需要保證進程可見,還需要考慮進程與鎖之間的網路問題。

分布式情況下之所以問題變得復雜,主要就是需要考慮到網路的延時和不可靠。分布式鎖還是可以將標記存在內存,只是該內存不是某個進程分配的內存而是公共內存如Redis、Memcache。至於利用資料庫、文件等做鎖與單機的實現是一樣的,只要保證標記能互斥就行。

❾ 如何用redis實現分布式鎖

Redis有一系列的命令,特點是以NX結尾,NX是Not eXists的縮寫,如SETNX命令就應該理解為:SET if Not eXists。這系列的命令非常有用,這里講使用SETNX來實現分布式鎖。

用SETNX實現分布式鎖

利用SETNX非常簡單地實現分布式鎖。例如:某客戶端要獲得一個名字foo的鎖,客戶端使用下面的命令進行獲取:

SETNX lock.foo <current Unix time + lock timeout + 1>

如返回1,則該客戶端獲得鎖,把lock.foo的鍵值設置為時間值表示該鍵已被鎖定,該客戶端最後可以通過DEL lock.foo來釋放該鎖。
如返回0,表明該鎖已被其他客戶端取得,這時我們可以先返回或進行重試等對方完成或等待鎖超時。
解決死鎖

上面的鎖定邏輯有一個問題:如果一個持有鎖的客戶端失敗或崩潰了不能釋放鎖,該怎麼解決?我們可以通過鎖的鍵對應的時間戳來判斷這種情況是否發生了,如果當前的時間已經大於lock.foo的值,說明該鎖已失效,可以被重新使用。

發生這種情況時,可不能簡單的通過DEL來刪除鎖,然後再SETNX一次,當多個客戶端檢測到鎖超時後都會嘗試去釋放它,這里就可能出現一個競態條件,讓我們模擬一下這個場景:

C0操作超時了,但它還持有著鎖,C1和C2讀取lock.foo檢查時間戳,先後發現超時了。
C1 發送DEL lock.foo
C1 發送SETNX lock.foo 並且成功了。
C2 發送DEL lock.foo
C2 發送SETNX lock.foo 並且成功了。
這樣一來,C1,C2都拿到了鎖!問題大了!

幸好這種問題是可以避免D,讓我們來看看C3這個客戶端是怎樣做的:

C3發送SETNX lock.foo 想要獲得鎖,由於C0還持有鎖,所以Redis返回給C3一個0
C3發送GET lock.foo 以檢查鎖是否超時了,如果沒超時,則等待或重試。
反之,如果已超時,C3通過下面的操作來嘗試獲得鎖:
GETSET lock.foo <current Unix time + lock timeout + 1>
通過GETSET,C3拿到的時間戳如果仍然是超時的,那就說明,C3如願以償拿到鎖了。
如果在C3之前,有個叫C4的客戶端比C3快一步執行了上面的操作,那麼C3拿到的時間戳是個未超時的值,這時,C3沒有如期獲得鎖,需要再次等待或重試。留意一下,盡管C3沒拿到鎖,但它改寫了C4設置的鎖的超時值,不過這一點非常微小的誤差帶來的影響可以忽略不計。
注意:為了讓分布式鎖的演算法更穩鍵些,持有鎖的客戶端在解鎖之前應該再檢查一次自己的鎖是否已經超時,再去做DEL操作,因為可能客戶端因為某個耗時的操作而掛起,操作完的時候鎖因為超時已經被別人獲得,這時就不必解鎖了。

示例偽代碼

根據上面的代碼,我寫了一小段Fake代碼來描述使用分布式鎖的全過程:

# get lock
lock = 0
while lock != 1:
timestamp = current Unix time + lock timeout + 1
lock = SETNX lock.foo timestamp
if lock == 1 or (now() > (GET lock.foo) and now() > (GETSET lock.foo timestamp)):
break;
else:
sleep(10ms)

# do your job
do_job()

# release
if now() < GET lock.foo:
DEL lock.foo
是的,要想這段邏輯可以重用,使用python的你馬上就想到了Decorator,而用Java的你是不是也想到了那誰?AOP + annotation?行,怎樣舒服怎樣用吧,別重復代碼就行。

❿ java怎麼實現redis分布式鎖

一、使用分布式鎖要滿足的幾個條件:

系統是一個分布式系統(關鍵是分布式,單機的可以使用ReentrantLock或者synchronized代碼塊來實現)
共享資源(各個系統訪問同一個資源,資源的載體可能是傳統關系型資料庫或者NoSQL)
同步訪問(即有很多個進程同事訪問同一個共享資源。沒有同步訪問,誰管你資源競爭不競爭)
二、應用的場景例子

管理後台的部署架構(多台tomcat伺服器+redis【多台tomcat伺服器訪問一台redis】+mysql【多台tomcat伺服器訪問一台伺服器上的mysql】)就滿足使用分布式鎖的條件。多台伺服器要訪問redis全局緩存的資源,如果不使用分布式鎖就會出現問題。 看如下偽代碼:

long N=0L;
//N從redis獲取值
if(N<5){
N++;
//N寫回redis
}
復制代碼