一 什么是緩存
1. 生活上的例子
比如有一個行李箱和一個手機,每次把手機放到行李箱在拿出來肯定很麻煩,如果放到褲兜里就會方便很多,所以褲兜算作行李箱的一個緩存,不僅僅是褲兜,甚至可以一直拿在手上等其他有存儲介質的東西。
說白了緩存就是用來提高效率的,比如 內存 作為 CPU 和 外設 的緩存,和接下來要講的 Redis 作為 MySQL 的緩存,MySQL 和磁盤打交道,磁盤是外設 I/O 效率慢,并且是隨機尋址就更慢了,而 Redis 工作在內存,用來緩存 MySQL 的部分數據來分攤壓力再合適不過了。
二 緩存如何更新
1. 定期更新
顧名思義:每隔一段時間來對緩存進行更新,比如每個一段時間統計訪問頻率最多的 100 個單詞寫入到日志里,到了時間在同步到 Redis 進行緩存更新。
定期更新帶來的問題:隔的這段時間可能某些冷門詞突然就變高頻了,但是定期更新,所以無法及時更新到緩存里,導致繞過 Redis ,壓力就導到 MySQL 中了,為了解決這個問題引入實時更新。
2. 實時更新
顧名思義:只要查不到緩存,就去 MySQL 中查,查到了在放到緩存里。
Redis 是跑在內存中的,內存大小有限,且不止有 Redis 這一個服務在使用,所以一直更新就會導致 Redis 占用內存直到內存用盡,所以引入了緩存淘汰策略。
3. 淘汰策略
1. FIFO(先進先出)
先進緩存的先淘汰。
2. LRU(最久未訪問的)
最久未訪問的先淘汰。
3. LFU(最少訪問次數)
最少訪問次數的先淘汰。
4. Random(隨機淘汰)
隨機淘汰。
5. Redis 支持的淘汰選項:
Volation-LRU:在設置了過期的 Key 中淘汰最久未訪問的。
AllKeys-LRU:在所有的?Key 中淘汰最久未訪問的。
Volation-LFU:在設置了過期的 Key 中淘汰最少訪問次數的。
AllKeys-LFU:在所有的 Key 中淘汰最少訪問次數的。
AllKeys-Random:在設置了過期的 Key 中隨機淘汰。
Volation-Randon:在所有的 Key 中隨機淘汰。
Volation-TTL:在設置了過期的 Key 中淘汰越早過期的。
Noeviction(默認策略):沒有任何淘汰機制,寫超了直接報錯(不適用與實時更新)。
三 緩存使用事項
1. 緩存預熱
緩存更新采用實時更新的時候:
原因:
- Redis 服務剛啟動,什么也沒有,壓力全部到 MySQL 中,并把查到的數據緩存到 Redis,一開始 MySQL 就會承擔大量的并發請求導致壓力過大。
解決辦法:
- 最開始的時候把 定期更新 和 實時更新 相結合,先把預先的高頻日志導到 Redis,后續在采用實時更新,避免了一開始大量并發到 MySQL。
定期更新沒有緩存預熱的情況。
2. 緩存穿透
當查詢某些?Key,Redis MySQL 中都不存在,MySQL 壓力也會增大。
原因:
- ?MySQL 刪除誤刪了數據。
- ?Key 本身不合法。
解決辦法:
- 對不合法的 Key 檢測。
- 采用布隆過濾器提前檢測 Key 是否存在。
3. 緩存雪崩
某一時間端大量的 Key 失效,導致 MySQL 壓力過大。
原因:
- 如果同一時間內設置了過期的?Key ,并且過期時間相同。
- Redis 服務掛了。
解決辦法:
- 過期時間添加其他因子避免過期時間相同。
- 引入集群,哨兵自動管理掛掉的 Redis 服務器。
4. 緩存擊穿
某一時間端熱點 Key 失效,導致 MySQL 壓力過大,和緩存雪崩類似。
原因:
- 和緩存雪崩類似。
解決辦法:
- 熱點 Key 盡量不要設置過期時間。
- 引入分布式鎖,訪問 MySQL 次數上限則鎖住,避免 MySQL 壓力過大。