<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] ## 一、緩存雪崩 緩存雪崩表示在某一時間段,緩存集中失效,導致請求全部走數據庫,有可能搞垮數據庫,使整個服務癱瘓。 使緩存集中失效的原因: 1、redis服務器掛掉了。 2、對緩存數據設置了相同的過期時間,導致某時間段內緩存集中失效。 如何解決緩存集中失效: 1、針對原因1,可以實現redis的高可用,Redis Cluster 或者 Redis Sentinel(哨兵) 等方案。 2、針對原因2,設置緩存過期時間時加上一個隨機值,避免緩存在同一時間過期。 ~~~php <?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、使用雙緩存策略,設置兩個緩存,原始緩存和備用緩存,原始緩存失效時,訪問備用緩存,備用緩存失效時間設置長點。 ~~~php //原始緩存 $redis->set('article_content_2', '文章內容', 60); //設置備用緩存,失效時間設置長點 $redis->set('article_content_backup_2', '文章內容', 1800); ~~~ ## 二、緩存穿透 緩存穿透表示查詢一個一定不存在的數據,由于沒有獲取到緩存,所以沒寫入緩存,導致這個不存在的數據每次都需要去數據庫查詢,失去了緩存的意義。 請求的數據大量的沒有獲取到緩存,導致走數據庫,有可能搞垮數據庫,使整個服務癱瘓。 比如文章表,一般我們的主鍵ID都是無符號的自增類型,有些人想要搞垮你的數據庫,每次請求都用負數ID,而ID為負數的記錄在數據庫根本就沒有。 解決方案: 1、對于像ID為負數的非法請求直接過濾掉,采用布隆過濾器(Bloom Filter)。 2、針對在數據庫中找不到記錄的,我們仍然將該空數據存入緩存中,當然一般會設置一個較短的過期時間。 ~~~php //設置文章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 <?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; } } ~~~ 個人見解:解決擊穿和穿透(key不存在),可以使用同一種方案:1.查詢key在緩存是否存在.2不存在 加鎖 去數據庫查詢獲取(沒有數據就存空字符),然后放入緩存,解鎖。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看