一 背景
二 分散式鎖介紹
1 什麼是分散式鎖

2 實現分散式鎖的主流方式
-
基於資料庫實現分散式鎖,此處的資料庫指的是MySQL關係型資料庫
-
基於MySQL鎖表 -
資料庫版本號樂觀鎖
-
基於快取實現分散式鎖,此處的快取指的是Redis
-
基於zookeeper/etcd實現分散式鎖
三 質量保障
1 事前質量保障
評估併發風險
技術選型
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 事中保障
CodeReview
1)Redis快取分散式鎖
-
Redis快取分散式鎖CodeReview注意點
-
Redis Key
-
全面梳理業務場景,對於同一共同資源,key要保持一致; -
key是識別共享資源的唯一鍵,key的設計既需要能夠鎖住當前共享資源又不能影響到其他資源;
-
鎖釋放
-
鎖一定需明確釋放,try/finally 結構加鎖解鎖,finally內釋放鎖; -
鎖只能被加鎖的物件釋放,此處是經常出問題的點,如下圖所示,A加鎖被B釋放鎖,導致鎖失效,鎖被C搶佔到;

-
鎖超時
-
一定要設定key的超時時間;例如:客戶端A 搶到鎖後,系統突然異常,A就無法釋放鎖,變成死鎖;設定超時時間就是為了防止此種情況發生,在時間到期後,自動刪除key,間接釋放鎖; -
超時時間的設定一般來講大於服務的最大執行時間即可,但是服務最大的執行時間會受很多因素影響,是不可控的;例如:A服務一般執行時間是30ms,設定的鎖超時時間為100ms,受網路影響服務執行時間變成了200ms,在100ms的時候鎖就會被釋放了;在大部分場景下,開發不會處理此種情況,此種極端情況是否需要處理,需要進行協商;處理方式如下2種: -
可以再開啟一個執行緒,為當前超時時間續時,但增加了系統的複雜度; -
將過期時間設定非常長,一定能保證邏輯在鎖釋放之前能夠執行完成;此方案簡單但是有缺陷,當遇到系統突發異常時,鎖無法被釋放,只能等待redis key超時,而超時時間又設定的較長,因此在當前時間內誰都無法獲取到鎖,阻斷業務執行,很有可能造成故障;

-
鎖粒度

-
獲取鎖失敗
2)MySQL資料庫鎖CR點
-
資料庫版本號樂觀鎖

-
where 條件一定要命中索引(最好是主鍵或者唯一索引),否則會鎖表; -
update table set 中必須要包含version = version + 1; -
update 返回結果為0時,一定要根據業務場景進行相應的處理,自主重試或者拋異常;
-
基於MySQL鎖表
併發測試
-
複雜的併發場景,一次請求共享資源存在多個,且前後存在各種依賴關係,此種場景適合於鏈路級別壓測,壓測模型需要精心設計。
-
單一併發場景,一個共享資源,可以處理多次,例如:扣除某個商品的庫存,可以反覆呼叫。
-
可以透過介面壓測的方式進行測試,透過檢視最終資料是否會存在與預期不一致情況即可; -
壓測工具:jmeter 即可進行壓測(集團可直接採用pas-server進行壓測,方便快捷);
-
單一併發場景,一個共享資源,且只能處理1次,例如:使用者只有一次抽獎機會,連續點2次會不會抽2次;
-
可以利用JVM的併發函式CountDownLatch,CyclicBarrier等,CountDownLatch片段程式碼:
publicvoidinvokeAllTask(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);
}
}
-
利用jmeter的定時器 Synchronizing Timer也可以實現此功能
3 事後保障
資料對賬
-
互動積分體系每個使用者的扣除以及增加積分都會落流水錶;每個使用者目前有多少積分都會放在積分表;只需要把流水錶的積分加總和積分表的積分進行對賬;
-
互動任務體系,一筆訂單隻能推進一個任務,對賬只需要檢查任務記錄中一筆訂單是否存在多條記錄;
selectcount(*) as task_count,
scene_code,
order_id
from task_record
where unique_id isnotnull
groupby scene_code,
order_id
havingcount(*)> 1
四 總結
-
梳理併發場景 -
帶著注意點CR 程式碼 -
併發測試(非銀彈,不是所有場景都具備可測性) -
監控對賬進行兜底識別併發問題
招聘
CentOS 8 的使用者請注意,請儘快切換映象源!
由於CentOS 8結束了生命週期,官方已經停止CentOS 8的維護,而阿里雲映象站的CentOS Linux公共映象來源於CentOS官方,所以阿里雲映象站也移除了相應的CentOS 8映象源。如果您是阿里雲CentOS 8映象源的使用者,並且您的業務過渡期仍需要使用CentOS 8中的一些安裝包,為了不影響您的使用,建議您切換至CentOS-Vault源, 具體配置請點選閱讀原文。

關鍵詞
資料
分散式鎖
問題
系統
執行緒