【新夢想老師分享】分散式鎖的正確"姿勢"
一、概述
在如今高併發、分散式大行其道的今天,如果你還只會單體專案,那未免也太落伍了。撇開技術落伍、受人恥笑外(臉皮厚的人根本不在乎恥笑),更為現實的問題是:如果你是剛進入職場的新人,即將面臨找工作,估計連面試機會都沒有;如果你是已經在職的人士,不知曉分散式的各種成人姿勢,那你也只有在公司任人玩弄的份。說到分散式這麼重要,那今天我作為一個潛伏IT圈多年的老將,跟大家分享下分散式下的分散式鎖的各種成人姿勢,注意是成人哦,未成年人勿入。
二、問題現場還原—秒殺系統下單功能
1.mysql資料庫有2張表:stock(庫存表) ,stock_order(訂單表)。
2.後臺透過spring boot構建下單的業務介面(下單流程=查庫存–下單–減庫存)。
3.開啟瀏覽器正常業務流程再現,重新整理多少次,賣出多少份皮蛋粥,沒毛病。
4.使用壓測工具(ab/jemter/loaderrunner)進行壓力測試ab -n 100 -c 100
5.再次開啟瀏覽器檢視庫存
各位看官,看到這個結果是不是有一種蛋碎一地的感覺!!! 怎麼可能10000份皮蛋粥可以賣出(9989+109),如果你感覺奇怪,那說明你的技術已經out了。好了到此場景還原就到此結束。接下來給各位介紹下解決這種問題的各種姿勢。
三、姿勢一:synchronized
瞭解多執行緒的同學肯定會想到,併發執行緒安全問題,可以用jdk同步工具synchronized解決。正確的說法給大家更正下,叫做資料庫丟失更新。能想到這裡的我算你有點社會實踐姿勢,但是效果如何,請看:
1.給下單方法加synchronized,做同步。
2.繼續壓力測試
ab -n 100 -c 100
3.synchronized姿勢總結:
1)是一種解決方案。
2)synchronized無法實現細粒度的鎖。
在下單的方法中加synchronized會將所有商品下單都做同步,如果另外一件商品並沒有很高併發量。也會導致很請求 很慢,鎖的粒度太大。
3)只適合單點情況。(而現實是高併發、分散式叢集當道)
四、姿勢二:分散式鎖
接下來是我們的主角:分散式鎖登場了。
分散式鎖的三種實現方式:資料庫分散式鎖、redis分散式鎖、zookeeper分散式鎖。今天打算給大家介紹下redis分散式鎖的實現方式。
1.安裝redis【不知道怎麼安裝的,請諮詢我的官方秘書度娘】
2.maven工程中匯入spring-redis依賴。
org.springframework.boot
spring-boot-starter-data-redis
3.編寫redisLock實現加鎖與解鎖
org.springframework.boot spring-boot-starter-data-redis
3.編寫redisLock實現加鎖與解鎖
/**
加鎖
@param key
@param value 當前時間+超時時間
@return
*/
public static boolean lock (String key ,String value){
//setIfAbsent=setNX 如果不存在,就設定值並返回true,否返回false
//1,加鎖成功 if(redisTemplate.opsForValue().setIfAbsent(key,value)){ return true; }
//2,避免死鎖(執行緒1加鎖成功,結果在解鎖前出現異常,沒有解鎖,導致死鎖)
//2.1獲取過期時間 StringcurrentValue=redisTemplate.opsForValue().get(key);
//2.2判斷過期時間於當前時間的關係
if(!StringUtils.isEmpty(currentValue)
&&Long.parseLong(currentValue)<System.currentTimeMillis()){String oldValue = redisTemplate.opsForValue().getAndSet(key,value); if(!StringUtils.isEmpty(oldValue)&&oldValue.equals(currentValue)){return true;
}
}
//3,加鎖失敗 t2結束 返回false
return false;
}
/**
解鎖
@param key
@param value
*/
public void unLock(String key,String value){
try {
String currentValue = redisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(currentValue)&¤tValue.equals(value)){
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e){
log.error("【redis分散式鎖】 解鎖異常");
}
}
4.下單方法加鎖、解鎖
@Override
public void orderProductMockDiffUser(String productId) throws Exception {
//【加鎖】
long time = System.currentTimeMillis()+TIMEOUT;
if(!redisLock.lock(productId,String.valueOf(time))){
throw new Exception(“人也太多了,換個姿勢在試試,~~~~”);
}
//1.查詢該商品庫存,為0則結束活動
int stockNum = stock.get(productId);
if(stockNum==0){
throw new Exception(“活動結束”);
}else{
//2.下單(模擬不同的使用者openid 不同)
orders.put(KeyUtil.genUniqueKey(),productId);
//3.減庫存
stockNum-=1;
try {
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
stock.put(productId,stockNum);
}
//3.解鎖
redisLock.unLock(productId,String.valueOf(time));
}
5.redis姿勢總結:
1)鎖的粒度小。(多個商品同時秒殺不會阻塞)
2)適合高併發,分散式叢集部署。
好啦,今天的內容就到此結束了,希望對大家理解分散式鎖有所幫助。
————————————————
版權宣告:本文為CSDN博主「newdreamtest」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/newdreamtest/article/details/103685399
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69940641/viewspace-2670310/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 「分散式」實現分散式鎖的正確姿勢?!分散式
- 掌握Redis分散式鎖的正確姿勢Redis分散式
- 這才是實現分散式鎖的正確姿勢!分散式
- redis應用系列一:分散式鎖正確實現姿勢Redis分散式
- 用Python解鎖“吃雞”正確姿勢Python
- TiDB 的正確使用姿勢TiDB
- Redis的正確使用姿勢Redis
- git commit 的正確姿勢GitMIT
- Postman 正確使用姿勢Postman
- Redis分散式鎖的正確實現方式Redis分散式
- Redis 分散式鎖的正確開啟方式Redis分散式
- 分散式事務的這些常見用法都有坑,來看看正確姿勢分散式
- 提意見的正確"姿勢"
- 使用快取的正確姿勢快取
- 擼.NET Core的正確姿勢
- laravel 使用 es 的正確姿勢Laravel
- 使用列舉的正確姿勢
- 開啟Git的正確姿勢Git
- 玩轉 Ceph 的正確姿勢
- 程式設計師玩連連看的正確姿勢程式設計師
- 分散式鎖實現的正確開啟方式分散式
- 開發函式計算的正確姿勢 —— 爬蟲函式爬蟲
- 原始碼|使用FutureTask的正確姿勢原始碼
- 在vscode使用editorconfig的正確姿勢VSCode
- 虛幻私塾的正確使用姿勢
- MySQL 5.6建索引的正確姿勢MySql索引
- Spring Boot使用AOP的正確姿勢Spring Boot
- 使用 react Context API 的正確姿勢ReactContextAPI
- Swift中使用Contains的正確姿勢SwiftAI
- 學習Linux命令的正確姿勢Linux
- npm run dev 的正確使用姿勢NPMdev
- 基於Redis分散式鎖的正確開啟方式Redis分散式
- 與單體式應用分手的7個正確姿勢
- 開發函式計算的正確姿勢——OCR 服務函式
- Homestead 開啟mongodb正確姿勢MongoDB
- Java日誌正確使用姿勢Java
- Spark streaming消費Kafka的正確姿勢SparkKafka
- 相容iphone x劉海的正確姿勢iPhone