什么是缓存穿透
看如下这个代码案例:
<?php
function getList($key)
{
$list = $redis->get($key);//查询缓存
if (!empty($list )) return $list ;
$list = $this->getDb();//没有查询到缓存,从数据库中获取
$redis->set($key,$list ,$time);//设置缓存
return $list ;
}
上述案例中没有缓存穿透解决方案,在高并发下,如果缓存过期,会有多个请求到数据库,导致数据库崩溃。
如何解决?
<?php
function getList($key){
$list = $redis->get($key);//查询缓存
if (!empty($list)) return $list;
$list= $this->getDb();//没有查询到缓存,从数据库中获取//如果缓存穿透后,数据库中没查询到数据,自定义数据,写入缓存
if (empty($list)) $list = [];
$redis->set($key,$list);
return $list;
}
在缓存失效情况下,如果只想要一个请求到数据库中,该怎么处理
<?php
function getList($key){
$data = $redis->get($key);//查询缓存
if (!empty($data)) {
//缓存未过期,返回数据
if ($data['expireTime']>time()) return $data['data'];
//缓存已过期,获取锁,如果未获取到锁,则返回过期数据
if (!$redis->setNx()) return $data['data'];
}
$list = $this->getDb();//从数据库中获取
if (empty($list)) $list = [];
$expireTime = 120;//缓存时间为 120秒//设置过期时间
$data = [
'data'=>$list,
'expireTime'=>$expireTime - 60
];
$redis->set($key,$data,$expireTime);
return $list;
}
上述方案可以解决缓存穿透,避免雪崩效应,加上锁机制,到达数据库的请求只有一个。
关于过期时间,使用我们自己的过期时间操作缓存数据有更大的灵活空间。缓存时间比我们业务定义的过期时间晚 60秒。这样,我们有60秒的时间刷新最新的数据到缓存数据库中。
网友评论