圖解C語言鎖

什麼是分散式鎖?它能幹sha?

單體系統中,在高併發場景下想要訪問共享資源的時候,我們需要透過加鎖的方式來保證共享資源併發的安全性,確保在同一時刻只有一個執行緒對共享資源進行操作。相信大家對於Java提供的synchronized關鍵字以及Lock鎖都不陌生,在實際的專案中大家都使用過。如下圖所示,在同一個JVM程序中,Thread1獲得鎖之後,對共享資源進行操作,其他執行緒未獲得鎖的執行緒只能等待Thread1釋放後才能進行對應的操作。

圖解C語言鎖

但是隨著業務的不斷髮展,原先的單體應用被拆分為多個微服務,每個微服務又會部署多個例項,於是就形成了當下的微服務架構。處理共享資源的請求來自不同的服務例項,也就是在不同的JVM程序中。原先的單體服務中的加鎖方式在分散式場景下不能滿足共享資源的併發訪問要求。因此我們需要一種適用於分散式場景下的共享資源安全的處理機制,此時應對這種問題的分散式鎖就應運而生了。

既然JVM程序管不到其他服務例項的執行緒,那麼可以藉助於外部元件能力來實現不同服務例項對於共享資源的統一管控,這種能力我們可以稱之為分散式鎖。因此分散式鎖的本質就是在不同服務例項之外建立一種獲取鎖的機制,形成一種併發互斥能力來確保不同執行緒對於共享資源的併發安全,從而實現在微服務架構中同一時刻只有一個執行緒可以對共享資源進行操作。對於分散式鎖來說,實際就是需要一個外部的狀態儲存系統來實現原子化的排他性操作。

圖解C語言鎖

透過對於分散式鎖的需求分析,總結了如下的分散式鎖四大特性,分別是多節點、加鎖速度快、排他性以及鎖過期實現機制。

圖解C語言鎖

分散式鎖實現方案

基於資料庫的分散式鎖實現方案

實現原理

透過資料庫的方式實現分散式鎖的效果,實際就是藉助於資料庫的唯一性約束特性或者for update來實現。這裡以唯一性約束來舉個栗子,在電商領域的庫存服務負責對商品的庫存進行扣減,首先建立一張專門存放鎖資訊的鎖表,那麼庫存服務在進行庫存操作之前,先向資料庫中的鎖表插入一條鎖資源資料。

create table ‘distributed_lock’ (

‘id’ BIGINT NOT NULL AUTO_INCREMENT,

‘resource_lock_key‘ varchar(64) NOT NULL

PRIMARY KEY(‘id’),

UNIQUE KEY ‘uk_resource_lock_key‘ (‘resource_lock_key‘) USING BTREE

大致的互動流程如下:

1、當庫存服務進行手機庫存扣減的時候,首先先向資料庫中的鎖表當中插入一條資源鎖資訊;

2、如果插入成功,則表示庫存服務1可以對手機庫存進行庫存扣減操作;

3、此時庫存服務2也要對庫存進行操作,於是同樣插入資料到鎖表中;

4、但是由於鎖表設定了唯一性約束,鎖資訊插入失敗,庫存服務進行等待;

5、庫存服務1執行完庫存扣減之後,刪除鎖表的資訊;

6、庫存服務2嘗試插入資源鎖資訊,發現可以插入成功,繼續執行後續操作。

圖解C語言鎖

方案分析

基於資料庫的實現方式,看起來還是比較容易理解的。但是實際上還是有一些問題存在的,我們一起來分析下。

1、效能問題:由於是插入資料資料需要落盤儲存,如果平凡進行讀寫的話會影響資料庫效能,另外由於使用唯一鍵進行判斷也會一定程度上影響資料庫效能,因此資料庫方案適用於併發量不到的簡單場景;

2、資料庫如果單點部署的話會存在單點故障問題,如果資料庫出現故障,可能會導致平臺中的業務異常;

3、死鎖問題:在上文介紹中,包含了插入資料庫的獲取鎖的步驟,還包含了刪除鎖資訊的釋放鎖的過程,但是如果庫存服務1在加鎖之後掛掉了,無法進行鎖的釋放,而其他服務又無法獲取到鎖就會造成死鎖的問題。當然了我們可以透過一個定時任務去檢查鎖表中是不是有過時的鎖資源。但是這樣無疑增加了分散式鎖實現的複雜性。

4、不支援可重入:如果想要實現可重入鎖,還需要增加主機、執行緒名等欄位來進行標註,透過這幾個欄位來判斷和當前資訊是否一致,如果一致則認為已經獲取到了鎖。

鑑於以上的這些問題,有沒有其他的分散式實現方案可以避免上述存在的問題呢?我們再往下來看。

基於Redis的分散式鎖實現方案

基於sentnx命令的實現原理

Redis作為一塊高效能的資料庫中介軟體,經常被當做快取在專案中使用。因此透過Redis實現分散式鎖,也是比較常見的實現方案。 一樣的道理,透過Redis實現分散式鎖也需要透過它實現鎖的互斥的能力。實際上就是利用了sentnx(set if not exists)命令。同時該命令是否能夠設定成功,決定服務是否可以拿到對應的分散式鎖。

127。0。0。1:6379> setnx stockLock 10。12。35。12_stockService

(integer) 1