新聞中心
這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
PHP+Redis解決緩存擊穿的實際問題
php+Redis解決實際問題:緩存擊穿

問題描述:
PHP+Redis如何簡單避免緩存擊穿
解決方案:
get($key);
//如果 非強(qiáng)制刷新 且 緩存非空 ,獲取鎖
if(!$refresh && !is_null($data)){
$lock = $redis->get($lockKey);
}
if(!$lock){//如果鎖過期或無數(shù)據(jù)
$lock=$redis->setnx($lockKey,1); //僅當(dāng)鎖不存在時設(shè)置鎖,值1代表數(shù)據(jù)獲取中
if($lock || $refresh){ //搶到新鎖 或 強(qiáng)制刷新
try {
$data=$func(); //從回調(diào)函數(shù)獲取要緩存的數(shù)據(jù)
//有數(shù)據(jù)則寫入緩存,沒有則刪除數(shù)據(jù)
if(!is_null($data)){
$redis->set($key,$data);
}else{
$redis->del([$key]);
}
$redis->set($lockKey,2,'ex',$expire); //設(shè)置鎖的過期時間,值2代表數(shù)據(jù)獲取完成
}catch (Exception $exception){
$redis->del([$lockKey]); //發(fā)生異常,刪除鎖
}
}else{
//如果沒有數(shù)據(jù),又沒有搶到鎖
//30秒內(nèi)每秒判斷搶到鎖的用戶是否執(zhí)行完成,執(zhí)行完成則從緩存得到數(shù)據(jù)并返回
$retry=0;
do{
sleep(1);
$retry++;
$data = $redis->get($key);
}while(is_null($data) && $redis->get($lockKey)==1 && $retry<30);
}
}
//寫入內(nèi)存
if(!is_null($data)){
$dataStatic[$key]=$data;
}
//返回數(shù)據(jù)
return $data;
}
代碼解讀:
-
數(shù)據(jù)本體永不過期
-
設(shè)置鎖的過期時間,鎖過期則搶到鎖的用戶刷新數(shù)據(jù)
-
未搶到鎖的用戶如果有拿到數(shù)據(jù)就直接返回(此時數(shù)據(jù)已經(jīng)是過期數(shù)據(jù),如果對數(shù)據(jù)及時性要求高的需要自己改造代碼)
-
未搶到鎖的用戶如果沒有拿到數(shù)據(jù)則每秒判斷搶到鎖的用戶是否執(zhí)行完成
-
鎖有極小概率變成死鎖,最好有定時任務(wù)定期處理,比如每天業(yè)務(wù)低谷期清理死鎖
文章題目:PHP+Redis解決緩存擊穿的實際問題
當(dāng)前URL:http://fisionsoft.com.cn/article/dhipggh.html


咨詢
建站咨詢
