溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

【新夢(mèng)想老師分享】分布式鎖的正確"姿勢(shì)"

發(fā)布時(shí)間:2020-03-03 13:40:03 來(lái)源:網(wǎng)絡(luò) 閱讀:244 作者:qq5ddf70848596b 欄目:軟件技術(shù)

一、概述


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


二、問(wèn)題現(xiàn)場(chǎng)還原—秒殺系統(tǒng)下單功能


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


2.后臺(tái)通過(guò)spring boot構(gòu)建下單的業(yè)務(wù)接口(下單流程=查庫(kù)存–下單–減庫(kù)存)。


3.打開(kāi)瀏覽器正常業(yè)務(wù)流程再現(xiàn),刷新多少次,賣出多少份皮蛋粥,沒(méi)毛病。




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


5.再次打開(kāi)瀏覽器查看庫(kù)存




各位看官,看到這個(gè)結(jié)果是不是有一種蛋碎一地的感覺(jué)?。?! 怎么可能10000份皮蛋粥可以賣出(9989+109),如果你感覺(jué)奇怪,那說(shuō)明你的技術(shù)已經(jīng)out了。好了到此場(chǎng)景還原就到此結(jié)束。接下來(lái)給各位介紹下解決這種問(wèn)題的各種姿勢(shì)。


三、姿勢(shì)一:synchronized


了解多線程的同學(xué)肯定會(huì)想到,并發(fā)線程安全問(wèn)題,可以用jdk同步工具synchronized解決。正確的說(shuō)法給大家更正下,叫做數(shù)據(jù)庫(kù)丟失更新。能想到這里的我算你有點(diǎn)社會(huì)實(shí)踐姿勢(shì),但是效果如何,請(qǐng)看:


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




2.繼續(xù)壓力測(cè)試


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




3.synchronized姿勢(shì)總結(jié):


1)是一種解決方案。


2)synchronized無(wú)法實(shí)現(xiàn)細(xì)粒度的鎖。


在下單的方法中加synchronized會(huì)將所有商品下單都做同步,如果另外一件商品并沒(méi)有很高并發(fā)量。也會(huì)導(dǎo)致很請(qǐng)求 很慢,鎖的粒度太大。


3)只適合單點(diǎn)情況。(而現(xiàn)實(shí)是高并發(fā)、分布式集群當(dāng)?shù)溃?/p>


四、姿勢(shì)二:分布式鎖


接下來(lái)是我們的主角:分布式鎖登場(chǎng)了。


分布式鎖的三種實(shí)現(xiàn)方式:數(shù)據(jù)庫(kù)分布式鎖、redis分布式鎖、zookeeper分布式鎖。今天打算給大家介紹下redis分布式鎖的實(shí)現(xiàn)方式。


1.安裝redis【不知道怎么安裝的,請(qǐng)咨詢我的官方秘書(shū)度娘】


2.maven工程中導(dǎo)入spring-redis依賴。


org.springframework.boot


spring-boot-starter-data-redis


3.編寫(xiě)redisLock實(shí)現(xiàn)加鎖與解鎖


org.springframework.boot spring-boot-starter-data-redis


3.編寫(xiě)redisLock實(shí)現(xiàn)加鎖與解鎖


/**


加鎖


@param key


@param value 當(dāng)前時(shí)間+超時(shí)時(shí)間


@return


*/


public static boolean lock (String key ,String value){


//setIfAbsent=setNX 如果不存在,就設(shè)置值并返回true,否返回false


//1,加鎖成功 if(redisTemplate.opsForValue().setIfAbsent(key,value)){ return true; }


//2,避免死鎖(線程1加鎖成功,結(jié)果在解鎖前出現(xiàn)異常,沒(méi)有解鎖,導(dǎo)致死鎖)


//2.1獲取過(guò)期時(shí)間 StringcurrentValue=redisTemplate.opsForValue().get(key);


//2.2判斷過(guò)期時(shí)間于當(dāng)前時(shí)間的關(guān)系


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結(jié)束 返回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(“人也太多了,換個(gè)姿勢(shì)在試試,~~~~”);


}


//1.查詢?cè)撋唐穾?kù)存,為0則結(jié)束活動(dòng)


int stockNum = stock.get(productId);


if(stockNum==0){


throw new Exception(“活動(dòng)結(jié)束”);


}else{


//2.下單(模擬不同的用戶openid 不同)


orders.put(KeyUtil.genUniqueKey(),productId);


//3.減庫(kù)存


stockNum-=1;


try {


Thread.sleep(100);


}catch (Exception e){


e.printStackTrace();


}


stock.put(productId,stockNum);


}


//3.解鎖


redisLock.unLock(productId,String.valueOf(time));


}


5.redis姿勢(shì)總結(jié):


1)鎖的粒度小。(多個(gè)商品同時(shí)秒殺不會(huì)阻塞)


2)適合高并發(fā),分布式集群部署。


好啦,今天的內(nèi)容就到此結(jié)束了,希望對(duì)大家理解分布式鎖有所幫助。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI