中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

【新夢想老師分享】分布式鎖的正確"姿勢"

發布時間:2020-03-03 13:40:03 來源:網絡 閱讀:246 作者:qq5ddf70848596b 欄目:軟件技術

一、概述


在如今高并發、分布式大行其道的今天,如果你還只會單體項目,那未免也太落伍了。撇開技術落伍、受人恥笑外(臉皮厚的人根本不在乎恥笑),更為現實的問題是:如果你是剛進入職場的新人,即將面臨找工作,估計連面試機會都沒有;如果你是已經在職的人士,不知曉分布式的各種成人姿勢,那你也只有在公司任人玩弄的份。說到分布式這么重要,那今天我作為一個潛伏IT圈多年的老將,跟大家分享下分布式下的分布式鎖的各種成人姿勢,注意是成人哦,未成年人勿入。


二、問題現場還原—秒殺系統下單功能


1.mysql數據庫有2張表:stock(庫存表) ,stock_order(訂單表)。


2.后臺通過spring boot構建下單的業務接口(下單流程=查庫存–下單–減庫存)。


3.打開瀏覽器正常業務流程再現,刷新多少次,賣出多少份皮蛋粥,沒毛病。




4.使用壓測工具(ab/jemter/loaderrunner)進行壓力測試ab -n 100 -c 100 http://127.0.0.1:8080/second-kill3/skill/order/123456


5.再次打開瀏覽器查看庫存




各位看官,看到這個結果是不是有一種蛋碎一地的感覺!!! 怎么可能10000份皮蛋粥可以賣出(9989+109),如果你感覺奇怪,那說明你的技術已經out了。好了到此場景還原就到此結束。接下來給各位介紹下解決這種問題的各種姿勢。


三、姿勢一:synchronized


了解多線程的同學肯定會想到,并發線程安全問題,可以用jdk同步工具synchronized解決。正確的說法給大家更正下,叫做數據庫丟失更新。能想到這里的我算你有點社會實踐姿勢,但是效果如何,請看:


1.給下單方法加synchronized,做同步。




2.繼續壓力測試


ab -n 100 -c 100 http://127.0.0.1:8080/second-kill3/skill/order/123456




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)&&currentValue.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)適合高并發,分布式集群部署。


好啦,今天的內容就到此結束了,希望對大家理解分布式鎖有所幫助。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

海南省| 保德县| 安阳市| 佛山市| 顺昌县| 乐都县| 宜春市| 通江县| 西丰县| 镇远县| 青铜峡市| 东辽县| 那坡县| 嘉义市| 繁峙县| 宜都市| 博白县| 全州县| 竹溪县| 于都县| 德清县| 砀山县| 阜平县| 丁青县| 天峨县| 哈尔滨市| 广丰县| 方山县| 南溪县| 景德镇市| 台中县| 永州市| 北安市| 潼南县| 砀山县| 江安县| 抚顺市| 汝南县| 永靖县| 鄂尔多斯市| 扶沟县|