緩存
緩存雪崩
就是緩存層裏的數據同一個時間點失效,那麼這些數據就會集中打向 MySQL。
緩存擊穿
緩存裏有一條數據,一條數據失效後也是穿過了 redis 打到了 MySQL。
緩存擊穿、緩存雪崩屬於緩存穿透的一種特殊表現形式。
緩存穿透
描述
當找 redis 找不到數據時候,就會出現緩存穿透。
低頻率的緩存穿透不可怕,正常現象。
當高頻率的穿透就影響大了。
黑客攻擊的場景,模擬很多客戶端發送 id = -1 的請求。
id = -1 在 redis 中找不到,穿過 redis 找到數據庫,數據處理不過來就崩了(拒絕服務攻擊DDOS)。
解決方案
-
通過 MySQL 中找不到的值緩存在 redis 中。(黑客太菜了)
當然第一次查詢 id = -1 的時候可能沒找到穿透了,但是這次我把 id = -1 放在了 redis 中。
id = -2 再查詢我再放。。。。也是大量的訪問數據庫。(UUID 黑盒 每次生成一個不一樣的 ID)
這個方案適得其反,redis 一定的數據淘汰策略(LRU、LFU…)如果每次都是 UUID,那麼真正需要緩存的數據就被淘汰了,redis 裏是一些垃圾數據。
-
過濾器(redis),這個過濾器把 MySQL 裏面的所有 id 號,放在 redis 和 MySQL 的中間(不行),不一定是通過 id 查詢或者 id 過多,這樣就會導致過濾器的效率太低,內存緊張,導致整個鏈路都很慢。
解決過濾器中數據過多的場景。布隆過濾器,通過一定的錯誤率降低內存的佔用。
比如 id = 100,傳給 hash 函數,來一個 bin(二進制, size=10) 數組,保證哈希結果在 0-9 之間。。。。。。
拿到 id = 100,計算出的 hash 相同,就會告訴客戶端你要的數據是有的。
錯誤發生在計算哈希上,如果布隆過濾器告訴你數據存在,那麼數據不一定存在。如果布隆過濾器告訴你數據不存在,那麼這個數據一定不存在。
寧可錯殺 3k 不放過一個。發生哈希碰撞就有可能是一次錯誤,數組的長度影響錯誤率。
和哈希函數的個數也有關係。布隆過濾器的簡單實現是 3 個 hash 函數計算的三個位置標示一個數據是否存在。哈希函數個數多了反而錯誤率升高。數組長度很長會增加內存佔用。
【人生中最重要的一個字“度”】,通過算法計算合適的 hash 函數個數和數組長度。通常的布隆過濾器會要求提供允許的錯誤率 fpp 和存儲的數據量 n。然後通過公式計算出數組大小 m 和 hash 函數的個數 k。
m = - ( n*ln(fpp) ) / ( ln(2) ^2 )
k = m/n * ln(2)
遇到刪除數據的情況?如果 id = 100 和 id = 10 的 hash 結果相同,我刪除了 id = 10 的數據,那麼布隆過濾器的這個 hash 結果的位置不能設爲 0,因爲還有數據對應。
如果場景中有頻繁的數據刪除情況,建議搞一個二維的數組,第二維的數組用來計數。(長度 100億佔用 1GB 左右)
面試題:文件 A 存了 100 億個URL,B 文件也是 100 億個 URL。只給一個 4GB 內存文件,快速找出 AB 的交集。
模糊算法
通過布隆過濾器來計算 A 中的,B 中的 URL,然後找到對應的交集。只需要一次的磁盤 IO 即可。
精準算法
A、B 兩個大文件拆分 1000 個放一個文件,分塊計算 hash 值然後對 1000 取餘。然後對A、B的小文件一一比較。拆分成小文件是爲了可以加載入內存中。
相同 URL 的 hash 值相同,取摸後也相同。所以會出現在 1-1 對應的小文件中。
EOF