Redis是個大話題,只要是去面試Java開發,幾乎必問。基礎一點的問Redis是什麼東西?用來做什麼?Redis支援哪些資料型別?Redis的效能為什麼那麼好?複雜一點的就會問到快取穿透、快取擊穿、快取雪崩等問題。而我在面試的時候也被問到了Redis為什麼用來做快取的問題。
所以我覺得很有必要總結一下Redis作為快取使用,可能會引發的問題。以達到溫故而知新的效果
ps:在本文章中,就不討論Redis能用來幹啥?這種基礎問題了
在討論Redis作為快取使用,可能會引發的問題之前,我們得了解官方是怎麼定義Redis
Redis是一個開源的記憶體中的資料結構儲存系統,它可以用作:資料庫、快取和訊息中介軟體。
它支援多種型別的資料結構,如字串(Strings),雜湊(Hash),列表(List),集合(Set),有序集合(Sorted Set或者是ZSet)。
Redis 內建了複製(Replication),LUA指令碼(Lua scripting), LRU驅動事件(LRU eviction),事務(Transactions) 和不同級別的磁碟持久化(Persistence),並通過 Redis哨兵(Sentinel)和自動分割槽(Cluster)提供高可用性(High Availability)。
Redis也提供了兩種持久化策略,這些策略可以讓使用者將自己的資料儲存到磁碟上面進行儲存。根據實際情況,可以每隔一定時間將資料集以快照的形式儲存在磁碟(RDB策略),或者將所有操作成功的命令追加到命令日誌中(AOF策略),它會在執行命令時,將被執行的命令複製到硬碟裡面,實現實時持久化資料的效果。當然,根據實際開發的需求,你也可以關閉持久化功能,單純的將Redis作為一個高效的網路的快取資料功能使用。
二、Redis作為快取使用,可能會引發的問題(重點)
Redis由C語言開發,並且將資料儲存在記憶體中,可以說Redis完全是基於記憶體進行操作,對資料讀寫的速度極快、效能極好。官方提供的資料是可以達到每秒100000+的吞吐量(每秒內查詢次數),如此優秀的機制使Redis極其適合作為快取使用。
1.快取穿透
程式在處理快取時,一般是先從快取查詢,如果快取沒有這個key(理解為資料),則會從資料庫中查詢,並將查詢到的資料儲存到快取中去。
好,問題來了,如果有個壞心眼的人向伺服器發起請求,去查詢一個一定不存在的資料,由於快取中沒有查到對應的資料時需要從資料庫查詢,查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到資料庫去查詢,快取形同虛設,這就是快取穿透。
解決方案:
1)最粗暴也是最常用的方法就是,如果一個查詢的資料為空(不管是資料不存在還是系統故障),我們就把這個空結果進行快取,但要把它的過期時間設定得很短,最長不超過5分鐘,這樣能有效的解決快取穿透問題。
2)其次,可以採用布隆過濾器,也能解決快取穿透問題
2.快取擊穿
快取擊穿和快取穿透在本質上很相似,都是查詢資料時快取失去了作用,導致請求直接去資料庫查詢資料,但是造成快取失效的原因卻是天差地別。
大量使用者在同一時間內訪問某熱點資料時,儲存在快取中的熱點資料卻突然失效(過期時間),結果就是大量的請求直接訪問資料庫,使資料庫的壓力變大,甚至導致資料庫當機,這就是快取擊穿。
解決方案:比較常用的方法是加互斥鎖(mutex)保證資料的一致性。簡單地來說,就是在快取失效的時候(判斷拿出來的值為空),不是立即去訪問資料庫,而是先使用快取工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set另一個請求所需要的資料,當操作返回成功時,再進行訪問資料庫的操作並回設快取;否則,就重試整個get快取的方法。
3.快取雪崩
如果快取的資料集中在一段時間內大批失效,而不巧的是在這段時間內又有大量使用者發起請求訪問資料,這樣就會造成大量的快取擊穿,所有的請求都會直接去訪問資料庫,導致資料庫在短時間內當機,這就是快取雪崩。
ps:這裡我使用了誇張的修辭手法。快取雪崩不一定會造成資料庫當機,但快取如果發生雪崩現象,那肯定是很嚴重的
解決方案:
1)加鎖排隊。加互斥鎖,新增資訊佇列
2)資料預熱。可以通過快取Reload機制,預先去更新快取,再即將發生大併發訪問前手動觸發載入快取不同的key,設定不同的過期時間,讓快取失效的時間點儘量均勻
3)設定熱點快取永不過時
筆者: 以上問題及解決方案純粹個人見解,如果有錯誤的地方,還請指正