php 原子缓存,PHP 缓存穿透/使用Redis进行缓存加锁

f9e83a4d4ec41bccd797726f84bb9e85.png

一 缓存穿透

缓存穿透指的是,当我们访问某个缓存KEY想取得对应的数据时,若此KEY不存在于缓存中,则会去查库。如何解决呢?将每次查询的结果都放入缓存不管是不是空。

public function getArticles($key)

{

$expire = 60 * 3;

$data = Cache::get($key);

//注意:此处使用is_null来判断而不是直接使用 (!$data)来判断。

//使用 (!$data)来判断的弊端是:如果$data的值为空字符串或者空数组,此处也是不成立的,会继续执行查询DB的语句,造成缓存穿透

if (!is_null($data)) {

return $data;

}

$data = $this->searchDB();

Cache::put($key, $data, $expire);

return $data;

}

当下一次访问时会直接返回,不会造成缓存穿透。

二 缓存加锁(Redis)

若系统的并发很高,当缓存过期时,则大量的请求会穿透缓存,同时到DB中查询,那我们可以设置缓存当缓存过期时,只去DB中请求一次并缓存吗?

可以,我们可以使用redis的setNx()setNx($key) 的作用类似于set($key) ,setNx的意思为 set Not Exists 如果$key不存在则设置,存在则不进行任何操作。

设置成功设置返回1,说明当前的请求获得了当前的操作权限,设置失败返回0,说明此资源已经被其他请求获得。

使用代码实现的话,思路如下:

①给存入缓存的数据增加一个过期时间字段暂时给这个字段起名字叫$data['expire'](这个过期时间要短于实际的缓存过期时间),方便在缓存过期前执行加锁和缓存更新。

②如果$data['expire']达到过期时间,则执行加锁以及缓存更新。

③此时如果有其他请求进入则返回更新之前的数据。

代码如下:

public function getArticlesLock($key)

{

$time = time();

$expire = 10 * 2;

$lockKey = 'lock:k';

$data = Cache::get($key);

if (!is_null($data)) {

//缓存未过期

if ($data['expire'] > time()){

return $data['data'];

}

//加锁失败说明已经有请求执行加锁,返回之前的缓存数据

if (!Redis::setnx($lockKey,1)) {

return $data['data'];

}

}

sleep(3);

$datat = $this->searchDB();

$data = [

'data' => $datat,

'expire' => $time + $expire - 10

];

$r = Cache::put($key, $data, $expire);

//解锁

Redis::del($lockKey);

return $data['data'];

}

当然此处也可以使用set()来代替setnx()加锁,以及使用lua脚本解锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值