并發(fā)大家都知道是什么情況,這里說(shuō)的是并發(fā)多個(gè)請(qǐng)求搶占同一個(gè)資源,直接上實(shí)例吧
請(qǐng)求:index.php?mod=a&action=b&taskid=6
處理:
$key = "a_b::".$uid."_".$taskid; $v = $redis->get($key); if($v == 1){ $redis->setex($key,10,1); //處理邏輯省略 }
邏輯看來(lái)還可以,結(jié)果發(fā)現(xiàn)數(shù)據(jù)庫(kù)中寫入了兩個(gè)同樣的請(qǐng)求結(jié)果,我看了記錄的時(shí)間戳,天!居然是同一秒.
我用microtime(true) log一下兩個(gè)請(qǐng)求的時(shí)間差居然相差了0.0001s,就是說(shuō)$redis->setex($key,10,1);還沒(méi)執(zhí)行成功 第二個(gè)請(qǐng)求已經(jīng)get到跟第一個(gè)請(qǐng)求一樣的結(jié)果。這不就是傳說(shuō)中的并發(fā)搶占資源。這中情況 聽(tīng)過(guò)很多,在開(kāi)發(fā)過(guò)程中也沒(méi)刻意去模擬實(shí)驗(yàn)過(guò)
第一反應(yīng)就是要給處理過(guò)程加事務(wù)(數(shù)據(jù)庫(kù)是mysql innoDB),加事務(wù)的結(jié)果就是 第一個(gè)請(qǐng)求成功了 第二個(gè)請(qǐng)求會(huì)執(zhí)行到后面撿查發(fā)現(xiàn)重了會(huì)回滾
其實(shí)mysql事務(wù)在保證數(shù)據(jù)一致性上是很ok的,但是通過(guò)回滾來(lái)保證唯一資源獨(dú)占代價(jià)太大,做過(guò)mysql事務(wù)測(cè)試測(cè)同學(xué)都知道,事務(wù)中的insert是已經(jīng)插進(jìn)去了,回滾之后才刪掉的。
還有一個(gè)選擇就是php中的文件獨(dú)占鎖,那就是說(shuō)這情況下我要新建 用戶數(shù) * 任務(wù)數(shù)的文件來(lái)實(shí)現(xiàn)每個(gè)請(qǐng)求資源的獨(dú)占,如果獨(dú)占資源較少的話可選的解決辦法:
/** * 加鎖 */ public function file_lock($filename){ $fp_key = sha1($filename); $this->fps[$fp_key] = fopen($filename, "w+"); if($this->fps[$fp_key]){ return flock($this->fps[$fp_key], LOCK_EX|LOCK_NB); } return false; } /** * 解鎖 */ public function file_unlock($filename){ $fp_key = sha1($filename); if($this->fps[$fp_key] ){ flock($this->fps[$fp_key] , LOCK_UN); fclose($this->fps[$fp_key] ); } }
發(fā)現(xiàn)$redis->setnx()可以提供原子操作的狀態(tài):相同的key執(zhí)行setnx之后沒(méi)過(guò)期或者沒(méi)del,再執(zhí)行會(huì)返回false。這就讓兩個(gè)以上的并發(fā)請(qǐng)求得到控制必須成功獲取鎖才能繼續(xù)。
下面的是我實(shí)現(xiàn)的代碼:
/** * 加鎖 */ public function task_lock($taskid){ $expire = 2; $lock_key ="task_get_reward_".$this->uid."_".$taskid; $lock = $this->redis->setNX($lock_key , time());//設(shè)當(dāng)前時(shí)間 if($lock){ $this->redis->expire($lock_key, $expire); //如果沒(méi)執(zhí)行完 2s鎖失效 } if(!$lock){//如果獲取鎖失敗 檢查時(shí)間 $time = $this->redis->get($lock_key); if(time() - $time >= $expire){//添加時(shí)間戳判斷為了避免expire執(zhí)行失敗導(dǎo)致死鎖 當(dāng)然可以用redis自帶的事務(wù)來(lái)保證 $this->redis->rm($lock_key); } $lock = $this->redis->setNX($lock_key , time()); if($lock){ $this->redis->expire($lock_key, $expire); //如果沒(méi)執(zhí)行完 2s鎖失效 } } return $lock; } /** * 解鎖 */ public function task_unlock($taskid){ $this->set_redis(); $lock_key = "task_get_reward_".$this->uid."_".$taskid; $this->redis->rm($lock_key); }
說(shuō)明下setNX 和expire 這兩個(gè)操作其實(shí)可以用redis事務(wù)來(lái)保證一致性
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/21934.html
摘要:這中情況聽(tīng)過(guò)很多,在開(kāi)發(fā)過(guò)程中也沒(méi)刻意去模擬實(shí)驗(yàn)過(guò)。這就讓兩個(gè)以上的并發(fā)請(qǐng)求得到控制必須成功獲取鎖才能繼續(xù)。 1.并發(fā)問(wèn)題并發(fā)大家都知道是什么情況,這里說(shuō)的是并發(fā)多個(gè)請(qǐng)求搶占同一個(gè)資源,直接上實(shí)例吧 請(qǐng)求:index.php?mod=a&action=b&taskid=6處理: $key = a_b::.$uid._.$taskid; $v = $redis->get($key); i...
摘要:鎖與很好的隔離使用者與實(shí)現(xiàn)者所需要關(guān)注的領(lǐng)域。那么這個(gè)就是包裝線程并且放入到隊(duì)列的過(guò)程實(shí)現(xiàn)的方法。也證實(shí)了就是獲取鎖的線程的節(jié)點(diǎn)。如果發(fā)生異常取消請(qǐng)求,也就是將當(dāng)前節(jié)點(diǎn)重隊(duì)列中移除。 前言 自從JDK1.5后,jdk新增一個(gè)并發(fā)工具包java.util.concurrent,提供了一系列的并發(fā)工具類。而今天我們需要學(xué)習(xí)的是java.util.concurrent.lock也就是它下面的...
摘要:其二如果返回值等于表示當(dāng)前線程獲取共享鎖成功,但它后續(xù)的線程是無(wú)法繼續(xù)獲取的,也就是不需要把它后面等待的節(jié)點(diǎn)喚醒。 在了解了AQS獨(dú)占鎖模式以后,接下來(lái)再來(lái)看看共享鎖的實(shí)現(xiàn)原理。 原文地址:http://www.jianshu.com/p/1161... 搞清楚AQS獨(dú)占鎖的實(shí)現(xiàn)原理之后,再看共享鎖的實(shí)現(xiàn)原理就會(huì)輕松很多。兩種鎖模式之間很多通用的地方本文只會(huì)簡(jiǎn)單說(shuō)明一下,就不在贅述了,...
摘要:前段時(shí)間的項(xiàng)目中遇到了并發(fā)操作阻塞問(wèn)題,因?yàn)檎?qǐng)求會(huì)使用存儲(chǔ)數(shù)據(jù)。不過(guò),這只限于來(lái)自同一個(gè)客戶端的多個(gè)請(qǐng)求,也就是說(shuō),來(lái)自一個(gè)客戶端的請(qǐng)求并不會(huì)阻塞另一個(gè)客戶端的請(qǐng)求。這將大大增加頁(yè)面的響應(yīng)時(shí)間。至此解決并發(fā)阻塞問(wèn)題。 ??前段時(shí)間的項(xiàng)目中遇到了session并發(fā)操作阻塞問(wèn)題,因?yàn)檎?qǐng)求會(huì)使用Session存儲(chǔ)數(shù)據(jù)。 ??在同一個(gè)客戶端瀏覽器打開(kāi)不同標(biāo)簽進(jìn)行測(cè)試的時(shí)候,請(qǐng)求一直處于等待狀態(tài)...
閱讀 2311·2021-10-11 10:59
閱讀 2602·2021-10-11 10:58
閱讀 3304·2021-09-08 09:35
閱讀 3783·2021-09-02 15:21
閱讀 1455·2019-08-30 15:53
閱讀 2608·2019-08-29 14:16
閱讀 2068·2019-08-26 14:00
閱讀 2942·2019-08-26 13:52