缓存的正确打开方式(一)

大的架构设计,各种高大上的概念层出不穷,相信很多人也或多或少的了解过,但其实,我们真的要把一个系统做强壮,做好,打磨细节才是根本,有句老话:细节是魔鬼,所以会来一系列的文章,来介绍各种细节上的问题,也欢迎大家多多投稿,本系列的开篇就是讲缓存

 

缓存,做为目前高并发系统的一个基石之一,已经是无处不在了,很多盆友认为如此成熟的技术,已经用的滚瓜烂熟了,没啥好说的吧

 

但是,真的是这样么?至少从我面试的一些情况来看,很多童鞋考虑的并不全面,下面以redis做为缓存为例,掰开来讲讲!

 

 

0x01 读的流程


 

基本流程如下:

public function getData($key)
{
    //获取缓存
    $data = $redis->get($key);

    //获取到缓存,直接返回
    if (!empty($data)) {
        return $data;
    }

    //没有缓存,则从DB获取数据
    $data = getDataFromDb($key);

    //数据写入缓存
    $redis->set($key, $data, $expireTime);

    //返回数据
    return $data;
}

 

这个应该是大部分人的代码流程,看起来没什么问题,但这里面有两个细节需要考虑

 

0x02 缓存穿透


 

问题1、如果数据库里也没有这个key的数据呢?

这种情况下,从redis取到的值必为空,从而导致:

 

//没有缓存,则从DB获取数据
$data = getDataFromDb($key);

 

每次都会去查数据库

这种情况,称之为缓存穿透

 

优秀如你,应该知道怎么优化了吧

 

//获取缓存
$data = $redis->get($key);

//获取到缓存,直接返回
if (!is_null($data)) {
    return $data;
}

//没有缓存,则从DB获取数据
$data = getDataFromDb($key);

//如果为空,则定义成一个空数组,可以根据自己

//情况设置成什么样的数据

if(empty($data)) {
$data = [];
}
//数据写入缓存
$redis->set($key, $data, $expireTime);

//返回数据
return $data;

 

即使db数据为空,我们也设置一个空数组到缓存中,然后通过 

is_null($data)

来判断,从而避免缓存穿透

 

0x03 缓存过期


 

问题2: 如果缓存时间正好过期,会发生什么情况?

 

这种情况下,如果系统的并发足够高,会导致很多的请求都穿透缓存,有点类似于缓存穿透, 理想状态,我们希望缓存失效时,只有一个请求走到DB,重建缓存

 

优秀如你,应该知道怎么优化了吧?

 

思路是,把缓存时间放到数据里进行判断,再通过一个锁机制保证只有一个请求能穿透到DB

 

public function getData($key)
{
    //获取缓存
    $data = $redis->get($key);

    //缓存未失效
    if (!is_null($data)) {
        
        //缓存未过期,直接返回
        if($data['expireTime'] > time()) {
            return $data['data'];
        }
        
        //缓存已过期,但未获得锁,返回数据,只让一个请求穿透
        //利用redis的setnx,实现锁
        if(!$redis->setNx()) {
            return $data['data'];
        }
        
    }

    //没有缓存,则从DB获取数据
    $rData = getDataFromDb($key);

    //如果为空,则定义成一个空数组,可以根据自己的情况设置
    if(empty($rData)) {
        $rData = [];
    }

    //过期时间提前60s
    $data = [
        'data' => $rData,
        'expireTime' => $expireTime - 60
    ];
    //数据写入缓存, 缓存
    $redis->set($key, $data, $expireTime);

    //返回数据
    return $rData;
}

 

这个在高并发的系统中,可以很好的防止同时很多请求都穿透到DB

 

读缓存的流程,你现在清楚了么?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值