掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
先了解一下什么是鎖,在單機系統(tǒng)中,多個線程同時改變一個變量時,需要對變量或者代碼塊做同步從而保證串行修改變量,該同步實質(zhì)上就是通過鎖來實現(xiàn)。為了實現(xiàn)多個線程在同一個時刻針對同一塊代碼串行執(zhí)行,就需要在某個地方做個標記,該標記必須每個線程都能看到,當標記不存在時可以設置該標記,其余后續(xù)線程發(fā)現(xiàn)已經(jīng)有標記了則等待擁有標記的線程結(jié)束同步代碼塊取消標記后再去嘗試設置標記,此標記可以理解為鎖。分布式鎖就是在多機系統(tǒng)下的該標記。

創(chuàng)新互聯(lián)主要從事網(wǎng)站建設、網(wǎng)站制作、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務平遠,十載網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:13518219792
目前分布式鎖的實現(xiàn)方式有3種主流方法,即:
1)基于數(shù)據(jù)庫實現(xiàn)分布式鎖,此處的數(shù)據(jù)庫指的是MySQL關(guān)系型數(shù)據(jù)庫;
2)基于緩存實現(xiàn)分布式鎖,此處的緩存指的是Redis;
3)基于zookeeper/etcd實現(xiàn)分布式鎖。
具體的關(guān)于鎖的實現(xiàn)方式,已經(jīng)有太多的文章進行介紹,本文就不再贅述。
并發(fā)問題一旦涉及到錢,通常都會導致不同程度的資損,而且在我們的功能測試中是很難發(fā)現(xiàn),因此對于并發(fā)的質(zhì)量保障顯得尤為的重要,可以抽象為3層來保障:事前、事中、事后三大步驟;事前保障通過Review 方式提前規(guī)避技術(shù)上的風險,事中保障驗證在技術(shù)實現(xiàn)過程中是否存在漏洞,事后保障校驗數(shù)據(jù)是否符合預期,對于有并發(fā)風險的項目上述三個步驟的保障缺一不可。
事前保障的階段發(fā)生在技術(shù)評審階段,在此階段,我們需要評估出當前業(yè)務場景下是否存在并發(fā)風險;如果存在,確定我們的技術(shù)選型。
評估并發(fā)風險的關(guān)鍵點在于是否存在多個進程同時訪問共享資源,簡單來說是否存在多個進程在同一時間對同一個數(shù)據(jù)進行更新的操作;例如:電商中的庫存,多人同時購買同一個商品,也就是會存在同一時間對同一個商品的庫存進行更新,此處就存在并發(fā)風險。
要做到正確的技術(shù)選型,我們就需要對上述3種方式實現(xiàn)的鎖的優(yōu)缺點以及應用場景需要進行了解。
MySQL數(shù)據(jù)庫表的樂觀鎖適用于讀多寫少的場景且共享資源為數(shù)據(jù)庫的單行數(shù)據(jù);MySQL表鎖實現(xiàn)的鎖一般都不推薦使用;ZooKeeper分布式鎖雖然適用于大部分分布式場景,但是由于其實現(xiàn)復雜度相對較高以及需要額外引入中間件,在大部分業(yè)務場景中的應用比較少,而基于Redis的緩存分布式鎖應用較為廣泛;但是具體業(yè)務實現(xiàn)采用哪種類型的分布式鎖,還是需要基于當前的業(yè)務特性來進行決定;
在技術(shù)評審階段,一方面我們要評估出是否存在并發(fā)風險,另外一方面,我們需要識別開發(fā)同學在技術(shù)的實現(xiàn)上可能存在的漏洞,針對分布式鎖的實現(xiàn)漏洞可參考下文的CodeReview的關(guān)注點。
① Redis緩存分布式鎖
Redis通??梢允褂胹etnx(key,value)函數(shù)來實現(xiàn)分布式鎖。key和value就是基于緩存的分布式鎖的兩個屬性,其中key表示鎖id。setnx函數(shù)返回1表示獲得鎖,返回0表示其他服務器已經(jīng)獲得了鎖;
Redis緩存分布式鎖CodeReview注意點:
a. Redis Key
例如:商品庫存,我們的key應該是具體到某個商品,而不是所有商品,鎖住A商品,不會影響B(tài)商品。
b. 鎖釋放
針對上述問題,釋放鎖時需要先讀取當前key的value,再和傳入的value進行比較;上述是兩個步驟一定要保證原子性,如果原生Redis可采用lua腳本保證原子性;如果tair,可采取TairString的cad方法;value必須是一個唯一值,唯一標記是當前對象加的鎖。
c. 鎖超時
可以再開啟一個線程,為當前超時時間續(xù)時,但增加了系統(tǒng)的復雜度;
將過期時間設置非常長,一定能保證邏輯在鎖釋放之前能夠執(zhí)行完成;此方案簡單但是有缺陷,當遇到系統(tǒng)突發(fā)異常時,鎖無法被釋放,只能等待redis key超時,而超時時間又設置的較長,因此在當前時間內(nèi)誰都無法獲取到鎖,阻斷業(yè)務執(zhí)行,很有可能造成故障。
d. 鎖粒度
如果針對某個共享資源的寫是基于另外一個共享資源的值計算而來,那么鎖的范圍必須包含讀共享資源;范圍不包含讀共享資源會導致臟讀,最終導致數(shù)據(jù)的錯誤,如下圖所示,Client B最終計算的B的結(jié)果就是錯誤的。
e. 獲取鎖失敗
由于其他線程已經(jīng)獲取到了鎖,當前線程獲取鎖失敗后有3種處理方式:異常拋出讓用戶重試;通過自旋再次進行搶鎖;發(fā)布訂閱,訂閱鎖釋放消息;在并發(fā)度低的場景下異常拋出以及自旋搶鎖都可以,在高并發(fā)場景下異常拋出和自旋搶鎖都不可取。
② MySQL數(shù)據(jù)庫鎖CR點
a. 數(shù)據(jù)庫版本號樂觀鎖
在數(shù)據(jù)庫的表中需要包含一個數(shù)字類型的字段version,讀取數(shù)據(jù)時把version字段讀出來,更新數(shù)據(jù)時判斷當前version是否等于讀取出來的version,并對當前version+1;如果等于就更新成功,不等于表示數(shù)據(jù)已過期更新失敗。例如以積分體系為例,存在多種場景增加積分,通過樂觀鎖來保證數(shù)據(jù)的正確性。
樂觀鎖CR注意點:
b. 基于MySQL鎖表
其實現(xiàn)原理是:創(chuàng)建一張鎖表,對臨界資源做唯一性約束,通過增加一條記錄對某一資源上鎖,釋放鎖時刪除記錄;一般不推薦此種用法。
并發(fā)測試總體上可以分為3大類:
a. 復雜的并發(fā)場景,一次請求共享資源存在多個,且前后存在各種依賴關(guān)系,此種場 景適合于鏈路級別壓測,壓測模型需要精心設計。
b. 單一并發(fā)場景,一個共享資源,可以處理多次,例如:扣除某個商品的庫存,可以 反復調(diào)用。
c. 單一并發(fā)場景,一個共享資源,且只能處理1次,例如:用戶只有一次抽獎機會, 連續(xù)點2次會不會抽2次;
public void invokeAllTask(ConcurrencyRequest request, Runnable task) {
final CountDownLatch startCountDownLatch = new CountDownLatch(1);
final CountDownLatch endCountDownLatch = new CountDownLatch(request.getConcurrency());
for (int i = 0; i < request.getConcurrency(); i++) {
Thread t = new Thread(() -> {
try {
startCountDownLatch.await();
try {
task.run();
} finally {
endCountDownLatch.countDown();
}
} catch (Exception ex) {
log.error("異常", ex);
}
});
t.start();
}
startCountDownLatch.countDown();
try {
endCountDownLatch.await();
} catch (InterruptedException ex) {
log.error("線程異常中斷", ex);
}
}數(shù)據(jù)對賬(數(shù)據(jù)一致性校驗)是我們在系統(tǒng)上線后對并發(fā)問題的最后一道防線,通過對賬來識別我們的數(shù)據(jù)的不一致性問題;壓測有成本,且受技巧熟練度和壓測設計的影響,不一定能暴露問題;如果被測場景評估并發(fā)問題的發(fā)生概率極低,即使發(fā)生了影響也比較小,此時review+對賬方式也不失為一種好的選擇;
如何進行對賬,不同的業(yè)務場景有不同的對賬方法,例如:
select count(*) as task_count,
scene_code,
order_id
from task_record
where unique_id is not null
group by scene_code,
order_id
having count(*)> 1
作為質(zhì)量保障同學一定要時刻繃著一根弦,當前場景下是否會存在并發(fā)問題;并發(fā)問題的識別簡單而言就是是否存在同時更新同一個數(shù)據(jù),如果是就一定要注意開發(fā)同學是否處理了并發(fā),并發(fā)的實現(xiàn)主要是上面闡述的幾種,然后按照場景進行分析即可;關(guān)于并發(fā)場景的質(zhì)量保障,大體原則可以概括為如下:

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流