redis缓存雪崩,缓存穿透,缓存击穿的php解决方法

本文介绍了PHP应对Redis缓存雪崩、穿透和击穿的解决方案。针对缓存雪崩,提出了实现Redis高可用、设置随机过期时间和使用双缓存策略;缓存穿透的解决方案包括过滤非法请求和使用布隆过滤器;缓存击穿的处理方法包括让热门key永不过期和使用互斥锁。
摘要由CSDN通过智能技术生成

一、缓存雪崩

缓存雪崩表示在某一时间段,缓存集中失效,导致请求全部走数据库,有可能搞垮数据库,使整个服务瘫痪。

使缓存集中失效的原因:

1、redis服务器挂掉了。

2、对缓存数据设置了相同的过期时间,导致某时间段内缓存集中失效。

如何解决缓存集中失效:

1、针对原因1,可以实现redis的高可用,Redis Cluster 或者 Redis Sentinel(哨兵) 等方案。

2、针对原因2,设置缓存过期时间时加上一个随机值,避免缓存在同一时间过期。

<?php
 
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 60);
$redis->auth('');
 
//设置过期时间加上一个随机值
$redis->set('article_content_1', '文章内容', 60 + mt_rand(1, 60));
$redis->set('article_content_2', '文章内容', 60 + mt_rand(1, 60));

3、使用双缓存策略,设置两个缓存,原始缓存和备用缓存,原始缓存失效时,访问备用缓存,备用缓存失效时间设置长点。

//原始缓存
$redis->set('article_content_2', '文章内容', 60);
//设置备用缓存,失效时间设置长点
$redis->set('article_content_backup_2', '文章内容', 1800);

二、缓存穿透

缓存穿透表示查询一个一定不存在的数据,由于没有获取到缓存,所以没写入缓存,导致这个不存在的数据每次都需要去数据库查询,失去了缓存的意义。

请求的数据大量的没有获取到缓存,导致走数据库,有可能搞垮数据库,使整个服务瘫痪。

比如文章表,一般我们的主键ID都是无符号的自增类型,有些人想要搞垮你的数据库,每次请求都用负数ID,而ID为负数的记录在数据库根本就没有。

解决方案:

1、对于像ID为负数的非法请求直接过滤掉,采用布隆过滤器(Bloom Filter)。

2、针对在数据库中找不到记录的,我们仍然将该空数据存入缓存中,当然一般会设置一个较短的过期时间。

//设置文章ID为-10000的缓存为空
$id = -10000;
$redis->set('article_content_' . $id, '', 60);
 
var_dump($redis->get('article_content_' . $id));

三、缓存击穿

缓存击穿表示某个key的缓存非常热门,有很高的并发一直在访问,如果该缓存失效,那同时会走数据库,压垮数据库。

缓存击穿与缓存雪崩的区别是这里针对的是某一热门key缓存,而雪崩针对的是大量缓存的集中失效。

解决方案:

1、让该热门key的缓存永不过期。

2、使用互斥锁,通过redis的setnx实现互斥锁。

<?php
 
function getRedis()
{
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379, 60);
    return $redis;
}
 
//加锁
function lock($key, $random)
{
    $redis = getRedis();
    //设置锁的超时时间,避免释放锁失败,del()操作失败,产生死锁。
    $ret = $redis->set($key, $random, ['nx', 'ex' => 3 * 60]);
    return $ret;
}
 
//解锁
function unLock($key, $random)
{
    $redis = getRedis();
    //这里的随机数作用是,防止更新缓存操作时间过长,超过了锁的有效时间,导致其他请求拿到了锁。
    //但上一个请求更新缓存完毕后,如果不加判断直接删除锁,就会误删其他请求创建的锁。
    if ($redis->get($key) == $random) {
        $redis->del($key);
    }
}
 
//从缓存中获取文章数据
function getArticleInCache($id)
{
    $redis = getRedis();
    $key = 'article_content_' . $id;
    $ret = $redis->get($key);
    if ($ret === false) {
        //生成锁的key
        $lockKey = $key . '_lock';
        //生成随机数,用于设置锁的值,后面释放锁时会用到
        $random = mt_rand();
        //拿到互斥锁
        if (lock($lockKey, $random)) {
            //这里是伪代码,表示从数据库中获取文章数据
            $value = $db->getArticle($id);
            //更新缓存,过期时间可以根据情况自已调整
            $redis->set($key, $value, 2 * 60);
            //释放锁
            unLock($lockKey, $random);
        } else {
            //等待200毫秒,然后重新获取缓存值,让其他获取到锁的进程取得数据并设置缓存
            usleep(200);
            getArticleInCache($id);
        }
    } else {
        return $ret;
    }
}

 

布隆过滤器是一种非常实用的解决缓存穿透缓存击穿缓存雪崩问题的工具。对于缓存穿透问题,布隆过滤器可以在缓存中存储空值,避免频繁查询数据库。布隆过滤器的原理是通过多次哈希运算将元素映射到一个二进制数组中,如果某个位置的值为1,则表示该元素可能存在;如果为0,则表示该元素一定不存在。通过布隆过滤器,可以快速判断一个请求是否需要查询数据库,从而避免了缓存穿透的问题。\[3\] 对于缓存击穿问题,布隆过滤器可以用于限流和降级策略。通过对热点参数进行限流,可以控制请求的并发量,避免数据库被大量请求压垮。同时,对于无效的请求,可以进行服务降级,直接返回默认值或错误信息,而不是查询数据库。\[2\] 对于缓存雪崩问题,布隆过滤器可以作为一种多级缓存的解决方案之一。除了使用Redis作为缓存外,还可以使用Nginx缓存等其他缓存工具,将请求分散到不同的缓存层,从而减轻数据库的访问压力。同时,可以通过设置缓存的过期时间,避免大量缓存同时过期,导致数据库访问压力过大。\[2\] 总之,布隆过滤器是一种非常实用的工具,可以有效解决Redis缓存雪崩缓存穿透缓存击穿问题。通过合理使用布隆过滤器,可以提高系统的性能和稳定性。 #### 引用[.reference_title] - *1* [redis缓存穿透之终极解决方案——布隆过滤器](https://blog.csdn.net/qq_40606397/article/details/114085367)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [redis缓存雪崩、击穿、穿透](https://blog.csdn.net/weixin_45414913/article/details/124901909)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值