為什么要使用分布式鎖

業務場景:

系統A是一個電商系統,目前是一臺機器部署,系統中有一個用戶下訂單的接口,但是用戶下訂單之前一定要去檢查一下庫存,確保庫存足夠了才會給用戶下單。

由于系統有一定的并發,所以會預先將商品的庫存保存在redis中,用戶下單的時候會更新redis的庫存。

此時系統架構如下:

但是這樣一來會產生一個問題:假如某個時刻,redis里面的某個商品庫存為1,此時兩個請求同時到來,其中一個請求執行到上圖的第3步,更新數據庫的庫存為0,但是第4步還沒有執行。

而另外一個請求執行到了第2步,發現庫存還是1,就繼續執行第3步。

這樣的結果,是導致賣出了2個商品,然而其實庫存只有1個。

很明顯不對啊!這就是典型的庫存超賣問題

我們很容易想到解決方案:用鎖把2、3、4步鎖住,讓他們執行完之后,另一個線程才能進來執行第2步。


按照上面的圖,在執行第2步時,使用Java提供的synchronized或者ReentrantLock來鎖住,然后在第4步執行完之后才釋放鎖。

Synchronized(this){

//扣減庫存邏輯代碼

……


}

這樣一來,2、3、4 這3個步驟就被“鎖”住了,多個線程之間只能串行化執行。

但是好景不長,整個系統的并發飆升,一臺機器扛不住了。現在要增加一臺機器,如下圖:


增加機器之后,系統變成上圖所示,我的天!

假設此時兩個用戶的請求同時到來,但是落在了不同的機器上,那么這兩個請求是可以同時執行了,還是會出現庫存超賣的問題。

為什么呢?因為上圖中的兩個A系統,運行在兩個不同的JVM里面,他們加的鎖只對屬于自己JVM里面的線程有效,對于其他JVM的線程是無效的。

因此,這里的問題是:Java提供的原生鎖機制在多機部署場景下失效了

這是因為兩臺機器加的鎖不是同一個鎖(兩個鎖在不同的JVM里面)。

那么,我們只要保證兩臺機器加的鎖是同一個鎖,問題不就解決了嗎?

此時,就該分布式鎖隆重登場了,分布式鎖的思路是:

在整個系統提供一個全局、唯一的獲取鎖的“東西”,然后每個系統在需要加鎖時,都去問這個“東西”拿到一把鎖,這樣不同的系統拿到的就可以認為是同一把鎖。

至于這個“東西”,可以是Redis、Zookeeper,也可以是數據庫。

文字描述不太直觀,我們來看下圖:


通過上面的分析,我們知道了庫存超賣場景在分布式部署系統的情況下使用Java原生的鎖機制無法保證線程安全,所以我們需要用到分布式鎖的方案。

那么,如何實現分布式鎖呢?請看我的下一篇文章

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。