1. 程式人生 > >redis分散式鎖的實現

redis分散式鎖的實現

最近專案中出現一個問題,就是在我的專案中,實現了一個商品搶購的功能,當專案執行起來後,使用者請求進來會去佔用商品,並下單搶購商品,開發完成後,沒有使用任何機制通過介面測試,ok沒問題,部署測試環境,開始測試後,發現會有多個人同時搶到我的這一件商品,這是腦子第一想到的是出現了執行緒安全問題,多個執行緒去爭取共享資源,然後就會出現這種超賣的現象,也就是我們所說的出現了執行緒不安全,這時候的處理方式是對縣城加鎖,假的是jdk中自帶的lock鎖,在進入執行的執行緒的時候,先去加上一把鎖,再去做裡邊的操作,然後最後在finally裡邊釋放鎖,ok在測試環境解決了超賣問題,但是我們的專案是叢集部署的,當專案部署到兩臺伺服器後,超賣問題又出現了,這次是什麼問題呢,排查後發現是因為jdk的lock鎖是在當前的jvm中式可以做到對執行緒加鎖的,但是兩臺伺服器後,那麼其實就有了兩個jvm。如果只剩下一件商品,兩個人搶購,每臺伺服器都接收到一個搶購請求,那麼就會出現兩個人都搶到了鎖,就又出現了超賣現象。這時候就可以引進這片文章的主題了   

不對的地方請大佬指出,小弟感激不盡

分散式鎖

分散式鎖的加鎖流程我們可以分為:搶鎖,加鎖,阻塞,釋放。

分散式鎖的實現可以簡單分為三種方式:

1.通過資料庫實現分散式鎖。

mysql使我們常用的資料庫,對於mysql的行級鎖我們也是很清楚的。對於資料庫的分散式鎖就是基於行級鎖實現的,還是我們上邊說的那種場景,兩個請求通過兩臺伺服器搶購同一件商品,線上程最開始的時候,我們可以向資料庫的一張表中插入一條id為1的資料,如果我們成功插入了那麼就認為加鎖成功,由於mysql的id不可重複這個時候另一個人的插入操作就會變成失敗的額,這個過程就是搶鎖和加鎖的步驟,然後去做你的業務,商品數量減一,這時候其他請求過來因為沒有搶到鎖會一直做不了任何事情在這裡就防止了超賣(阻塞),做完後,釋放鎖(釋放鎖就是把這條資料刪除就可以了),這時候另一個請求來查詢發現鎖已經被釋放了,這個請求進去後看到的是已經被買完的商品。這樣,就簡單呢的防止了超賣。這種方式是簡單,但是效能不是很高,不推薦使用。

2.通過redis實現分散式鎖。

實現思想有點類似於mysql的,但是是基於redis,redis有一個叫做setNX的命令

這個命令就是想redis裡邊插入一條資料

key:redis資料的key值   uuid:就是對應的value 

“NX”表示使用nx模式 :若給定的 key 已經存在,則 SETNX 不做任何動作。SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。

“PX” 表示超時時間以毫秒為單位,後邊的100000表示100秒的超時時間

ok,看過上邊引數的解讀對於setnx命令也應該有了瞭解,其實就是我們上邊使用資料庫行級鎖的插入資料那一步操作,如果已經存在就返回失敗(加鎖失敗),不存在就插入並返回ok(加鎖成功),這個時候其他請求進來都會顯示加鎖失敗,保證了執行緒的安全。

解鎖操作我們會使用一個lua指令碼實現,保證我們的操作原子性,也為了避免誤刪

這個就是在刪除的時候吧我們當時進去的value和現在的value做對比,如果一直就刪除,這是為了防止誤刪鎖。

下邊直接上程式碼:

不對的地方請大佬指出,小弟感激不盡

3第三種就是使用zokkerper做分散式鎖

目前小弟正在研究中,後期貼出來