溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何解決redis緩存穿透、緩存擊穿、緩存雪崩的問題

發(fā)布時(shí)間:2021-01-29 09:40:25 來源:億速云 閱讀:152 作者:小新 欄目:關(guān)系型數(shù)據(jù)庫

這篇文章主要介紹了如何解決redis緩存穿透、緩存擊穿、緩存雪崩的問題,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

  • 緩存穿透:key中對應(yīng)的緩存數(shù)據(jù)不存在,導(dǎo)致去請求數(shù)據(jù)庫,造成數(shù)據(jù)庫的壓力倍增的情況

  • 緩存擊穿:redis過期后的一瞬間,有大量用戶請求同一個(gè)緩存數(shù)據(jù),導(dǎo)致這些請求都去請求數(shù)據(jù)庫,造成數(shù)據(jù)庫壓力倍增的情,針對一個(gè)key而言

  • 緩存雪崩:緩存服務(wù)器宕機(jī)或者大量緩存集中某個(gè)時(shí)間段失效,導(dǎo)致請求全部去到數(shù)據(jù)庫,造成數(shù)據(jù)庫壓力倍增的情況,這個(gè)是針對多個(gè)key而言

一、緩存穿透的解決方案

  • 常用方法可以采用布隆過濾器方法進(jìn)行數(shù)據(jù)攔截,其次可以還有一種解決思路,就是如果請求的數(shù)據(jù)為空,將空值也進(jìn)行緩存,就不會(huì)發(fā)生穿透情況

<?php
class getPrizeList {
    /**
     * redis實(shí)例
     * @var \Redis
     */
    private $redis;

    /**
     * @var string
     */
    private $redis_key = '|prize_list';

    /**
     * 過期時(shí)間
     * @var int
     */
    private $expire = 30;

    /**
     * getPrizeList constructor.
     * @param $redis
     */
    public function __construct($redis)
    {
        $this->redis = $redis;
    }

    /**
     * @return array|bool|string
     */
    public function fetch()
    {
        $result = $this->redis->get($this->redis_key);
        if(!isset($result)) {
            //此處應(yīng)該進(jìn)行數(shù)據(jù)庫查詢...
            //如果查詢結(jié)果不存在,給其默認(rèn)空數(shù)組進(jìn)行緩存
            $result = [];
            $this->redis->set($this->redis_key, $result, $this->expire);
        }

        return $result;
    }
}

二、緩存擊穿解決辦法

  • 使用互斥鎖(mutex key),就是一個(gè)key過期時(shí),多個(gè)請求過來允許其中一個(gè)請求去操作數(shù)據(jù)庫,其他請求等待第一個(gè)請求成功返回結(jié)果后再請求。

<?php
class getPrizeList {
    /**
     * redis實(shí)例
     * @var \Redis
     */
    private $redis;

    /**
     * @var string
     */
    private $redis_key = '|prize_list';

    /**
     * @var string
     */
    private $setnx_key = '|prize_list_setnx';

    /**
     * 過期時(shí)間
     * @var int
     */
    private $expire = 30;

    /**
     * getPrizeList constructor.
     * @param $redis
     */
    public function __construct($redis)
    {
        $this->redis = $redis;
    }

    /**
     * @return array|bool|string
     */
    public function fetch()
    {
        $result = $this->redis->get($this->redis_key);
        if(!isset($result)) {
            if($this->redis->setnx($this->setnx_key, 1, $this->expire)) {
                //此處應(yīng)該進(jìn)行數(shù)據(jù)庫查詢...
                //$result = 數(shù)據(jù)庫查詢結(jié)果;
                $this->redis->set($this->redis_key, $result, $this->expire);
                $this->redis->del($this->setnx_key); //刪除互斥鎖
            } else {
                //其他請求每等待10毫秒重新請求一次
                sleep(10);
                self::fetch();
            }
        }

        return $result;
    }
}

三、緩存雪崩的解決辦法

  • 這種情況是因?yàn)槎鄠€(gè)key同時(shí)過期導(dǎo)致的數(shù)據(jù)庫壓力,一種方法可以在key過期時(shí)間基礎(chǔ)上增加時(shí)間隨機(jī)數(shù),讓過期時(shí)間分散開,減少緩存時(shí)間過期的重復(fù)率

  • 另一種方法就是加鎖排隊(duì),這種有點(diǎn)像上面緩存擊穿的解決方式,但是這種請求量太大,比如5000個(gè)請求過來,4999個(gè)都需要等待,這必然是指標(biāo)不治本,不僅用戶體驗(yàn)性差,分布式環(huán)境下就更加復(fù)雜,因此在高并發(fā)場景下很少使用

  • 最好的解決方法,是使用緩存標(biāo)記,判斷該標(biāo)記是否過期,過期則去請求數(shù)據(jù)庫,而緩存數(shù)據(jù)的過期時(shí)間要設(shè)置的比緩存標(biāo)記的長,這樣當(dāng)一個(gè)請求去操作數(shù)據(jù)庫的時(shí)候,其他請求拿的是上一次緩存數(shù)據(jù)

<?php
class getPrizeList {
    /**
     * redis實(shí)例
     * @var \Redis
     */
    private $redis;

    /**
     * @var string
     */
    private $redis_key = '|prize_list';

    /**
     * 緩存標(biāo)記key
     * @var string
     */
    private $cash_key = '|prize_list_cash';

    /**
     * 過期時(shí)間
     * @var int
     */
    private $expire = 30;

    /**
     * getPrizeList constructor.
     * @param $redis
     */
    public function __construct($redis)
    {
        $this->redis = $redis;
    }

    /**
     * @return array|bool|string
     */
    public function fetch()
    {
        $cash_result = $this->redis->get($this->cash_key);
        $result = $this->redis->get($this->redis_key);
        if(!$cash_result) {
            $this->redis->set($this->cash_key, 1, $this->expire);
            //此處應(yīng)該進(jìn)行數(shù)據(jù)庫查詢...
            //$result = 數(shù)據(jù)庫查詢結(jié)果, 并且設(shè)置的時(shí)間要比cash_key長,這里設(shè)置為2倍;
            $this->redis->set($this->redis_key, $result, $this->expire * 2);
        }

        return $result;
    }
}

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“如何解決redis緩存穿透、緩存擊穿、緩存雪崩的問題”這篇文章對大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI