分布式鎖在分布式應用中應用廣泛,想要搞懂乙個新事物首先得了解它的由來,這樣才能更加的理解甚至可以舉一反三。
首先談到分布式鎖自然也就聯想到分布式應用。
在我們將應用拆分為分布式應用之前的單機系統中,對一些併發場景讀取公共資源時如扣庫存,賣車票之類的需求可以簡單的使用同步或者是加鎖就可以實現。
但是應用分布式了之後系統由以前的單程序多執行緒的程式變為了多程序多執行緒,這時使用以上的解決方案明顯就不夠了。
因此業界常用的解決方案通常是借助於乙個第三方元件並利用它自身的排他性來達到多程序的互斥。如:
這裡主要基於 redis 進行討論。
既然是選用了 redis,那麼它就得具有排他性才行。同時它最好也有鎖的一些基本特性:
這裡利用redis set key
時的乙個 nx 引數可以保證在這個 key 不存在的情況下寫入成功。並且再加上 ex 引數可以讓該 key 在超時之後自動刪除。
所以利用以上兩個特性可以保證在同一時刻只會有乙個程序獲得鎖,並且不會出現死鎖(最壞的情況就是超時自動刪除 key)。
實現**如下:
private static final string set_if_not_exist = "nx";private static final string set_with_expire_time = "px";
public boolean trylock(string key, string request) else else if (jedis instanceof jediscluster)else else finally {
redislock.unlock(key,request) ;
使用很簡單。這裡主要是想利用 spring 來幫我們管理 redislock 這個單例的 bean,所以在釋放鎖的時候需要手動(因為整個上下文只有乙個 redislock 例項)的傳入 key 以及 request(api 看起來不是特別優雅)。
也可以在每次使用鎖的時候 new 乙個 redislock 傳入 key 以及 request,這樣倒是在解鎖時很方便。但是需要自行管理 redislock 的例項。各有優劣吧。
專案原始碼在:
歡迎討論。
在做這個專案的時候讓我不得不想提一下單測。
因為這個應用是強依賴於第三方元件的(redis),但是在單測中我們需要排除掉這種依賴。比如其他夥伴 fork 了該專案想在本地跑一遍單測,結果執行不起來:
有可能是 redis 的 ip、埠和單測裡的不一致。
redis 自身可能也有問題。
也有可能是該同學的環境中並沒有 redis。
所以最好是要把這些外部不穩定的因素排除掉,單測只測我們寫好的**。
於是就可以引入單測利器mock
了。
它的想法很簡答,就是要把你所依賴的外部資源統統遮蔽掉。如:資料庫、外部介面、外部檔案等等。
@testpublic void trylock() throws exception {
string key = "test";
string request = uuid.randomuuid().tostring();
mockito.when(jediscluster.set(mockito.anystring(), mockito.anystring(), mockito.anystring(),
mockito.anystring(), mockito.anylong())).thenreturn("ok");
boolean locktest = redislock.trylock(key, request);
system.out.println("locktest=" + locktest);
assert.asserttrue(locktest);
//check
mockito.verify(jediscluster).set(mockito.anystring(), mockito.anystring(), mockito.anystring(),
mockito.anystring(), mockito.anylong());
這裡只是簡單演示下,可以的話下次仔細分析分析。
它的原理其實也挺簡單,debug 的話可以很直接的看出來:
這裡我們所依賴的 jediscluster 其實是乙個cglib **物件
。所以也不難想到它是如何工作的。
比如這裡我們需要用到 jediscluster 的 set 函式並需要它的返回值。
mock 就將該物件**了,並在實際執行 set 方法後給你返回了乙個你自定義的值。
這樣我們就可以隨心所欲的測試了,完全把外部依賴所遮蔽了。
至此乙個基於 redis 的分布式鎖完成,但是依然有些問題。
感興趣的朋友還可以參考 redisson 的實現。
基於redis的分布式鎖
public class redislock 加鎖 取到鎖加鎖,並返回值用於解鎖 取不到鎖則立即返回 1 param millitimeout 最長鎖定時間,超時後自動刪除鎖,避免死鎖 return public synchronized long lock long millitimeout lo...
基於Redis的分布式鎖
the real target is that i was asked theredis鎖usage in the interview.and i cann t answer it.真正目的是因為在面試中被問到多執行緒這塊怎麼實現的,當時只是看了下 是用redis鎖實現的,至於具體的細節。自己回答的...
基於redis的分布式鎖
因為伺服器使用了集群方案。詞窮。實現乙個查詢資料庫,在大於0的情況下減庫存這樣小小的功能。測試 模擬100併發並看結果 public string reducestock else return helloworld 用測壓工具測壓結果 出現併發問題 單機測試結果 沒有問題 分布式測試結果 出現執行...