1. 程式人生 > >深入瞭解Redis(7)-快取穿透,雪崩,擊穿

深入瞭解Redis(7)-快取穿透,雪崩,擊穿

  redis作為一個記憶體資料庫,在生產環境中使用會遇到許多問題,特別是像電商系統用來儲存熱點資料,容易出現快取穿透,雪崩,擊穿等問題。所以實際運用中需要做好前期處理工作。

一、快取雪崩

1、概念

快取雪崩,是指在某一個時間段,快取集中過期失效。其實這個挺好理解的,舉個例子,假如我們把首頁的熱點資料都設定為1小時過期,剛好這個時候有個秒殺活動,大量的使用者請求直接打到資料庫。資料庫直接被打掛,如果沒做好高可用策略,跟這個資料庫相關的介面會報錯。即使重啟資料庫,也會被新的使用者請求打掛。這種大面積奔潰俗稱快取雪崩。

2、解決方案

看了上面的例子,就會發現解決方案很簡單,只需要讓快取不要在同一時間點失效。可以採取不同分類的資料,使用不同週期的失效時間。同一分類的資料,在失效時間上加入隨機因子。如果是特別熱門的資料,也可以設定永遠不過期,有更新操作再更新快取就可以。

二、快取擊穿

1、概念

快取擊穿跟快取雪崩是一個道理,只不過擊穿是一個點,雪崩是大量快取key,同樣是承受著高併發。具體是指一個key非常熱點,在不停的扛著大併發,大併發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大併發就穿破快取,直接請求資料庫,就像在一個屏障上鑿開了一個洞。

2、解決方案

其實這個更簡單,如果有這種型別的資料,直接設定永不過期即可。

三、快取穿透

1、概念

快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷髮起請求,我們資料庫的 id 都是1開始自增上去的,如發起為id值為 -1 的資料或 id 為特別大不存在的資料。這時的使用者很可能是攻擊者,攻擊會導致資料庫壓力過大,嚴重會擊垮資料庫。

2、解決方案

快取穿透的解決方案比較多,下面列兩個解決方案。

  • 一般來說,我們查詢到資料庫返回的物件為空時,就不會放入快取。但針對這個問題,我們可以先對請求引數做引數校驗,不合法的引數直接return,不經過快取和資料庫。如果從資料庫查詢的物件為空,也放入快取,只是設定的快取過期時間較短,比如設定為60秒。如果是同一ip反覆攻擊,可以直接讓運維拉黑。
  • redis自帶一個高階用法:Bloom Filter。這個也能很好的防止快取穿透的發生,他的原理也很簡單就是利用高效的資料結構和演算法快速判斷出你這個Key是否在資料庫中存在,不存在你return就好了,存在你就去查了DB重新整理KV再return。

Bloom Filter簡單運用

public class App {
 
    /**
     * 自定義過濾器
     */
    private static final String NAME = "specialBloom";
 
    /**
     * 初始容量
     */
    private static final long INIT_CAPACITY = 10000;
 
    /**
     * 錯判率
     */
    private static final double ERROR_RATE = 0.0001;
 
    public static void main(String[] args) {
        Client client = new Client("127.0.0.1", 7001);
        
        //client.delete(NAME);
        
        // 新建一個自定義過濾器
        client.createFilter(NAME, INIT_CAPACITY, ERROR_RATE);
 
        // 批量新增
        client.addMulti(NAME, "foo", "bar", "baz", "bat", "bag");
 
        String key = "foo";
 
        // 判斷key是否存在過濾器中 存在 true 不存在false
        boolean result = client.exists(NAME, key);
        log.info("判斷 [{}]NAME過濾器中,結果為 -> [{}]", key, result);
    }
 
}