分析Redis中熱點key儲存問題,聊聊快取異常的解決方法
這篇文章帶大家聊聊Redis中的三種常見快取異常:快取穿透、快取擊穿和快取雪崩,透過它們來聊一聊Redis中的熱點key儲存問題,希望對大家有幫助!
快取穿透、快取擊穿和快取雪崩是Redis面試當中和實際開發中,經常需要考慮的問題。很多人對該問題的產生、原因和解決方案還是不夠清晰。其實大家針對該三種情況,去仔細分析一個產生的原理就能很好的找到一個好的解決方案。 【相關推薦:Redis影片教學】
本文透過定義、案例、危害和解決方案的幾個角度,來幫助你快速了解該三個問題。
相信大家在網路上也看到很多解決這三種問題的解決方案,其中的一些方案是否是一個正確的
方案呢?本文也將一一分析此類方案的優缺點。
下圖為本文的內容大綱,文章也是圍繞這幾點進行分析與總結。
三個比較
#快取穿透、快取擊穿和快取雪崩都是因為快取中資料不存在,導致走資料庫去查詢資料。
由於快取資料不存在,所有的請求都會走到資料庫,因此會導致資料庫的壓力過大甚至出現服務崩潰,導致整個系統無法使用。
快取穿透
#定義:快取穿透是由於客戶端求的資料在快取中不存在,然後去查詢資料庫,然而資料庫沒有客戶端要查詢的數據,導致每一次請求都會走資料庫查詢操作。 真正的問題在於該資料本身就是不存在的
。
範例:客戶端要求商品詳情資訊時,攜帶一個商品ID,此時該商品ID是不存在的(不管是快取中還是資料庫中)。導致每一次要求該ID商品的資料資訊都會走資料庫。
危害:由於請求的參數對應的資料根本不存在,會導致每一次都會請求資料庫,增加資料庫的壓力或服務崩潰,更有甚至影響到其他的業務模組。經常發生在使用者惡意請求
的情況下會發生。
解決方案:
1、根據請求的參數快取一個null值。並且為該值設定一個過期時間,可以將時間設定短暫一點。
2、使用布隆過濾器,先透過布隆過濾器進行篩選,如果在過濾器中存在則去查詢資料庫,然後再加入到快取中。如果不存在則直接傳回客戶端資料不存在。
3、由於快取穿透可能是使用者發起惡意請求,可以將使用者ip給記錄下來,針對惡意的ip請求進行封鎖。
方案分析:
第一個方案,針對不存在的key,會快取一個空的值。假設這樣的請求特別多,是否都會一一去設定一個空值的緩存,此時Redis中就存在大量無效的緩存空值。假設這樣的key是商品或文章類別的ID,我們在設定空值之後,如果後台加入資料應該去更新ID對應的快取值,並設定一個合理的過期時間。
第二種方案,也是業界使用最多的方案。布隆過濾器的優點在於基於Redis實現,記憶體操作且底層的實作也是非常節約記憶體。當後台新增資料成功時,將該資料的ID加入到布隆過濾器中,前端在請求時先走布隆過濾器進行驗證是否存在。但布隆過濾器也存在一個弊端,就是hash衝突問題。這裡的hash衝突是什麼意思呢?是說多個ID在進行hash計算時,得到的hash位元都是同一個值,這就導致在驗證是否存在時誤判。本身是有的,得到的結果是沒有。
布隆過濾器的一個弊端就是,它說有不一定有,它說沒有就一點是沒有的。
第三種方案,針對同一用戶一段時間內發起大量的請求,觸發快取穿透機制,此時我們可以顯示該客戶端的存取。但攻擊者如果是發動DDOS這樣的攻擊,是沒辦法完全的避免此類攻擊,因此這種方案不是一個很好的解決方案。
方案總結:
#我們先在請求層級增加第3中方案,做一個限流機制、IP黑名單機制,控制一些惡意的請求,如果是誤判我們可以實現IP解封這樣的操作。在快取層則使用第1中方案實作。設定一個合理的快取時間。
對於能容忍誤判的業務場景,可以直接才用第2方案實現。完全基於Redis,減少了系統的複雜度。
快取擊穿
#定義:快取擊穿是因為某個熱點key不存在,導致走資料庫查詢。增加了資料庫的壓力。這種壓力可能是瞬間的,也可能是比較持久的。 真正的問題在於該key是存在,只是快取中不存在,導致走資料庫操作
。
範例:有一個熱門的商品,用戶查看商品詳情時攜帶商品的ID以獲取到商品的詳情資訊。此時快取中的資料已經過期了,因此來的所有請求都要走資料庫去查詢。
危害:相對快取穿透而言,該資料在資料庫中是存在的,只是因為快取過期了,導致要走一次資料庫,然後在加入到快取中,下次請求就能正常走快取.所謂的危害同樣的還是針對資料庫層面的危害。
解決方案:
1、加互斥鎖。針對第一個請求,發現快取中沒有數據,此時查詢資料庫加入到快取裡面。這樣後面的請求就不需要走資料庫查詢。
2、增加業務邏輯過期時間。在設定快取時,我們可以新增一個快取過期時間。每次去讀取的時候,做一個判斷,如果這個過期時間與當前時間小於一個範圍,觸發一個後台線程,去數據庫拉取一下數據,接著更新一下緩存數據和緩存的過期時間。其實原理就是程式碼層面給快取延長快取時長。
3、資料預熱。實作透過後台把資料加到快取裡面。例如秒殺場景開始前,就把商品的庫存加到快取裡面,這樣使用者請求來了之後,就直接走快取。
4、永久不過期。在給快取設定過期時間時,讓它永久不過期。後台單獨開啟一個線程,來維護這些快取的過期時間和資料更新。
方案分析:
互斥鎖保證了只有一個請求走資料庫,這是一個優點。但是對於分散式的系統,得才用分散式鎖實現,分散式鎖的實作本身就有一定的困難,這樣提升了系統的複雜度。
第2種方案,利用Redis不過期,業務過期的方案實現。保證了每一次請求都能拿到數據,同時也可以做到一個後台執行緒去更新數據。缺點在於後台執行緒沒有更新完數據,此時請求拿到的數據是舊數據,可能對應即時性要求高的業務場景有弊端。
第3種方案,使用快取預熱每次載入都走緩存,與第2種方案差不多。不過也存在熱點資料更新問題,因此此方案適合資料即時性要求不高的資料。
第4中方案,和第2、3種方案類似,在此基礎上進行了一定優化,使用後台非同步執行緒主動去更新快取資料。難點在於更新的頻率控制。
方案總結:
#對於即時性要求高的數據,推薦使用第1種方案,雖然在技術上有一定的難度但是能做到數據的即時性處理。如果發生某些請求等待時間久,可以傳回異常,讓客戶端重新發送一次請求。
對於即時性要求不高的數據,可以使用第4種方案。
快取雪崩
# 定義:前面說到快取擊穿,是因為快取中的某個熱點key失效,導致大量請求走資料庫。然而緩存雪崩其實也是同樣的道理,只不過這個更嚴重而已,是大部分緩存的key失效,而不是一個或者兩個key失效。
範例:在一個電商系統中,某一個分類下的商品資料在快取中都失效了。然而當前系統的許多請求都是該分類下面的商品資料。這樣就導致所有的請求都走資料庫查詢。
危害:由於一瞬間大量的請求湧入,每個請求都要走資料庫進行查詢。資料庫瞬間流量湧入,嚴重增加資料庫負擔,容易導致資料庫直接癱瘓。
解決方案:
1、快取時間隨機。因為某一時間,大量的快取失效,說明快取的過期時間比較集中。我們直接將過期的時間設定為不集中,隨機打亂。這樣快取過期時間相對不會很集中,就不會出現同一時刻大量請求走資料庫進行查詢操作。
2、多層快取。不單純的靠Redis來做緩存,我們也可以使用memcached來做緩存(這裡只是舉一個例子,其他的快取服務也可以)。快取資料時,對Redis做一個緩存,對memcached做一個快取。如果Redis失效了,我們可以走memcached。
3、互斥鎖。快取擊穿中我們提到了使用互斥鎖來實現,同樣我們也可以用在雪崩的情況下。
4、設定過期標誌。其實也可以用到快取擊穿中講到的永久不過期。當請求時,判斷過期時間,如果臨近過期時間則設定過期標誌,觸發一個獨立的執行緒去對這個快取進行更新。
方案分析:
第1種方案採用隨機數快取時間,能確保key的失效時間分散。困難在於如何設定快取時間,如果對於一些需要設定短快取時間並且資料量非常大的數據,則該方案就需要合理的控制時間。
第2種方案使用多層緩存,可以保證請求全部走緩存資料。但這樣增加了系統的架構難度,以及其他的各種問題,例如快取多層次更新。
第3種方案使用互斥鎖,在快取擊穿中我們提到了互斥鎖,在雪崩的場景中我們雖然能使用,但是這樣會產生大量的分佈式鎖。
第4種方案使用邏輯快取時間,很好的保證了系統的快取壓力。
方案總結:
在實際的專案中推薦使用第1、2和4種方案試下會更好一些。
總結
快取穿透是因為資料庫本身沒有該資料。
快取擊穿和快取雪崩是資料庫中存在該數據,只是快取中的資料失效了,導致重新要查詢一次資料庫再加入到快取中去。
快取擊穿是針對部分熱點key,而快取雪崩是大面積快取失效。兩則原理上其實是一樣的,無非就是針對快取的key的劃分不同而已。
更多程式設計相關知識,請造訪:程式設計入門! !
以上是分析Redis中熱點key儲存問題,聊聊快取異常的解決方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Redis集群模式通過分片將Redis實例部署到多個服務器,提高可擴展性和可用性。搭建步驟如下:創建奇數個Redis實例,端口不同;創建3個sentinel實例,監控Redis實例並進行故障轉移;配置sentinel配置文件,添加監控Redis實例信息和故障轉移設置;配置Redis實例配置文件,啟用集群模式並指定集群信息文件路徑;創建nodes.conf文件,包含各Redis實例的信息;啟動集群,執行create命令創建集群並指定副本數量;登錄集群執行CLUSTER INFO命令驗證集群狀態;使

如何清空 Redis 數據:使用 FLUSHALL 命令清除所有鍵值。使用 FLUSHDB 命令清除當前選定數據庫的鍵值。使用 SELECT 切換數據庫,再使用 FLUSHDB 清除多個數據庫。使用 DEL 命令刪除特定鍵。使用 redis-cli 工具清空數據。

要從 Redis 讀取隊列,需要獲取隊列名稱、使用 LPOP 命令讀取元素,並處理空隊列。具體步驟如下:獲取隊列名稱:以 "queue:" 前綴命名,如 "queue:my-queue"。使用 LPOP 命令:從隊列頭部彈出元素並返回其值,如 LPOP queue:my-queue。處理空隊列:如果隊列為空,LPOP 返回 nil,可先檢查隊列是否存在再讀取元素。

在CentOS系統上,您可以通過修改Redis配置文件或使用Redis命令來限制Lua腳本的執行時間,從而防止惡意腳本佔用過多資源。方法一:修改Redis配置文件定位Redis配置文件:Redis配置文件通常位於/etc/redis/redis.conf。編輯配置文件:使用文本編輯器(例如vi或nano)打開配置文件:sudovi/etc/redis/redis.conf設置Lua腳本執行時間限制:在配置文件中添加或修改以下行,設置Lua腳本的最大執行時間(單位:毫秒)

使用 Redis 指令需要以下步驟:打開 Redis 客戶端。輸入指令(動詞 鍵 值)。提供所需參數(因指令而異)。按 Enter 執行指令。 Redis 返迴響應,指示操作結果(通常為 OK 或 -ERR)。

使用Redis進行鎖操作需要通過SETNX命令獲取鎖,然後使用EXPIRE命令設置過期時間。具體步驟為:(1) 使用SETNX命令嘗試設置一個鍵值對;(2) 使用EXPIRE命令為鎖設置過期時間;(3) 當不再需要鎖時,使用DEL命令刪除該鎖。

使用 Redis 命令行工具 (redis-cli) 可通過以下步驟管理和操作 Redis:連接到服務器,指定地址和端口。使用命令名稱和參數向服務器發送命令。使用 HELP 命令查看特定命令的幫助信息。使用 QUIT 命令退出命令行工具。

Redis數據過期策略有兩種:定期刪除:定期掃描刪除過期鍵,可通過 expired-time-cap-remove-count、expired-time-cap-remove-delay 參數設置。惰性刪除:僅在讀取或寫入鍵時檢查刪除過期鍵,可通過 lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-user-del 參數設置。
