1. 程式人生 > 其它 >快取穿透,快取擊穿,快取雪崩解決方法

快取穿透,快取擊穿,快取雪崩解決方法

快取穿透

快取的目的是為了緩解 CPU 或者 I/O 的壓力,譬如對資料庫做快取,大部分流量都從快取中直接返回,只有快取未能命中的資料請求才會流到資料庫中,這樣資料庫壓力自然就減小了。

如果查詢的資料在資料庫中根本不存在的話,快取裡自然也不會有,
這類請求的流量每次都不會命中,這種查詢不存在資料的現象被稱為快取穿透。

快取穿透有可能是業務邏輯本身就存在的固有問題,也有可能是被惡意攻擊的所導致,為了解決快取穿透,通常會採取下面兩種辦法:

  1. 對於業務邏輯本身就不能避免的快取穿透,可以約定在一定時間內對返回為空的 Key 值依然進行快取(注意是正常返回但是結果為空,不應把拋異常的也當作空值來快取了),使得在一段時間內快取最多被穿透一次。

    如果後續業務在資料庫中對該 Key 值插入了新記錄,那應當在插入之後主動清理掉快取的 Key 值。如果業務時效性允許的話,也可以將對快取設定一個較短的超時時間來自動處理。

  2. 對於惡意攻擊導致的快取穿透,通常會在快取之前設定一個布隆過濾器來解決。所謂惡意攻擊是指請求者刻意構造資料庫中肯定不存在的 Key 值,然後傳送大量請求進行查詢。布隆過濾器是用最小的代價來判斷某個元素是否存在於某個集合的辦法。如果布隆過濾器給出的判定結果是請求的資料不存在,那就直接返回即可,連快取都不必去查。雖然維護布隆過濾器本身需要一定的成本,但比起攻擊造成的資源損耗仍然是值得的。

快取擊穿

我們都知道快取的基本工作原理是首次從真實資料來源載入資料,完成載入後回填入快取,以後其他相同的請求就從快取中獲取資料,緩解資料來源的壓力。

如果快取中某些熱點資料忽然因某種原因失效了,譬如典型地由於超期而失效,此時又有多個針對該資料的請求同時傳送過來,這些請求將全部未能命中快取,都到達真實資料來源中去,導致其壓力劇增,這種現象被稱為快取擊穿。

要避免快取擊穿問題,通常會採取下面的兩種辦法:

  1. 加鎖同步,以請求該資料的 Key 值為鎖,使得只有第一個請求可以流入到真實的資料來源中,其他執行緒採取阻塞或重試策略。如果是程序內快取出現問題,施加普通互斥鎖即可,如果是分散式快取中出現的問題,就施加分散式鎖,這樣資料來源就不會同時收到大量針對同一個資料的請求了。

  2. 熱點資料由程式碼來手動管理,快取擊穿是僅針對熱點資料被自動失效才引發的問題,對於這類資料,可以直接

    由開發者通過程式碼來有計劃地完成更新、失效,避免由快取的策略自動管理。**

快取雪崩

快取擊穿是針對單個熱點資料失效,由大量請求擊穿快取而給真實資料來源帶來壓力。有另一種可能是更普遍的情況,不需要是針對單個熱點資料的大量請求,而是由於大批不同的資料在短時間內一起失效,導致了這些資料的請求都擊穿了快取到達資料來源,同樣令資料來源在短時間內壓力劇增。

出現這種情況,往往是系統有專門的快取預熱功能,也可能大量公共資料是由某一次冷操作載入的,這樣都可能出現由此載入快取的大批資料具有相同的過期時間,在同一時刻一起失效。還有一種情況是快取服務由於某些原因崩潰後重啟,此時也會造成大量資料同時失效,這種現象被稱為快取雪崩。要避免快取雪崩問題,通常會採取下面的三種辦法:

  1. 提升快取系統可用性,建設分散式快取的叢集

  2. 啟用透明多級快取,各個服務節點一級快取中的資料通常會具有不一樣的載入時間,也就分散了它們的過期時間。

  3. 將快取的生存期從固定時間改為一個時間段內的隨機時間,譬如原本是一個小時過期,那可以快取不同資料。

總結

穿透:快取不存在,資料庫不存在,高併發,少量key。

擊穿:快取不存在,資料庫存在,高併發,少量key。

雪崩:快取不存在,資料庫存在,高併發,大量key。

Reference

《鳳凰架構》