相關推薦:《PHP Redis解決
訂單限流
的實際問題》
PHP Redis解決實際問題:快取擊穿
1、本系列文章每期都將解決一個Redis實際問題
2、每期問題將在每期的評論中選取
3、問題限Redis相關,其它問題如果本人感興趣也不排除開闢新系列
4、本人常用PHP所以解決方案以PHP為主
5、評論裡沒有合適的提問時我會自己給自己出題
問題描述:
本期為第二期,依舊是自己出題【狗頭】
PHP Redis如何簡單避免快取擊穿
解決方案:
<?php /** * 防击穿缓存 * @param string $key 缓存key * @param int $expire 缓存过期时间(s) * @param bool $refresh 是否强制刷新数据 * @param callable $func 获取要缓存的数据的回调方法(仅支持返回类型:?string) * @return null|string 返回缓存的值,没有值时且没有抢到刷新权且缓存已过期时返回null */ function onceCache(string $key,int $expire,bool $refresh,callable $func): ?string { //内存,注:如果是cli模式不要使用 static $dataStatic=[]; //读取内存 if(isset(self::$dataStatic[$key])){ return self::$dataStatic[$key]; } //获取laravel的获取redis连接,其它框架需要修改 $redis=Redis::connection(); //原缓存key加后缀"lock"为锁的key $lockKey=$key.':lock'; //锁是否有效 $lock=false; //读取数据 $data=$redis->get($key); //如果 非强制刷新 且 缓存非空 ,获取锁 if(!$refresh && !is_null($data)){ $lock = $redis->get($lockKey); } if(!$lock){//如果锁过期或无数据 $lock=$redis->setnx($lockKey,1); //仅当锁不存在时设置锁,值1代表数据获取中 if($lock || $refresh){ //抢到新锁 或 强制刷新 try { $data=$func(); //从回调函数获取要缓存的数据 //有数据则写入缓存,没有则删除数据 if(!is_null($data)){ $redis->set($key,$data); }else{ $redis->del([$key]); } $redis->set($lockKey,2,'ex',$expire); //设置锁的过期时间,值2代表数据获取完成 }catch (Exception $exception){ $redis->del([$lockKey]); //发生异常,删除锁 } }else{ //如果没有数据,又没有抢到锁 //30秒内每秒判断抢到锁的用户是否执行完成,执行完成则从缓存得到数据并返回 $retry=0; do{ sleep(1); $retry++; $data = $redis->get($key); }while(is_null($data) && $redis->get($lockKey)==1 && $retry<30); } } //写入内存 if(!is_null($data)){ $dataStatic[$key]=$data; } //返回数据 return $data; }
程式碼解讀:
推薦學習:《PHP影片教學
》
以上是PHP+Redis解決快取擊穿的實際問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!