基於Redis實現簡單的分佈式鎖

分佈式鎖要點

  1. 不一樣的節點訪問到的應該是同一把鎖。
  2. 鎖的基本特新不變,須要有加鎖和釋放兩大操做。
  3. 一個最重要的,不像JVM的鎖,在單機上,可使用try-catch-finally來進行鎖的釋放,可是分佈式鎖,加鎖和釋放鎖都是經過網絡的,因此要考慮一個節點獲取鎖以後萬一崩掉了沒有釋放鎖的場景。
  4. 其餘還有不少細節,我這裏只說明一個簡單的分佈式鎖須要注意的地方,能知足80%的需求。

加鎖實現說明

基於Redis的單線程特性和Lua腳本,咱們能夠簡單的實現一把分佈式鎖。通常鎖在Redis上就是一個KV值,加鎖就是新建一個KV,釋放鎖就把這個KV刪除。利用Redis在設置KV時能夠設置NX和PX特性,咱們就能夠很方便的加鎖。廢話很少說,先上僞代碼:git

String kId = UuidUtil.uuid();
String result = jedis.set("lockName", kId, "NX", "PX", 30 * 1000);

在獲取鎖時,先在本地生成uuid,做爲鎖的鑰匙。而後用這個uuid做爲值去redis設置KV,同時指定NX模式,NX模式的意思就是若是不存在才新增這個KV,若是對應的K已經存在,則放棄新增。這裏返回的result=OK表示新增成功即加鎖成功,否者加鎖失敗。後面兩個參數PX表明,這個KV有一個過時時間,若是時間過時了,KV會被自動的刪除。這個就是解決了上面說到的,若是一個節點沒有即時返回鎖,那麼防止死鎖的出現,這裏有個鎖持有的超時時間。redis

釋放實現說明

釋放鎖很簡單,就是直接刪除這個KV。可是咱們要作到的是,誰獲取鎖誰纔有資格釋放,因此在釋放時,不能簡單的根據K來刪除,還須要匹配V的值,這樣才能保證誰拿的鎖,誰有資格釋放。如此一來,釋放鎖就須要兩個步驟。第一步:先獲取當前鎖對應的值,和本身手上的鑰匙是否匹配。第二步,在匹配符合時再操做刪除。因此這裏就要用Lua腳原本保證這兩個步驟的原子性。僞代碼以下:網絡

String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
redis.eval(script, Collections.singletonList("lockName"), Collections.singletonList(kId));

簡單說明一下,這裏在本地編寫一段Lua腳本,大體意思你應該也能夠看出來了,先get取到鎖對應的值,判斷持有的kId是否相等,若是相等才進行del操做,進行鎖的刪除釋放。redis能夠原子的讓這個腳本執行。分佈式

所有代碼

剛纔說的所有代碼實現,在這個開源項目裏面有,裏面還有一些別的分佈式組件,若是對你有幫助,請給我個star哈。 https://gitee.com/xuan698400/distributed-toolui

相關文章
相關標籤/搜索