Redis——實戰問題彙總
Redis快取流程及問題和解決方案
1. 快取處理流程
前端請求資料,先從快取伺服器讀取資料,快取伺服器讀取成功直接返回結果。快取伺服器找不到資料從資料庫讀取,讀取成功後更新快取伺服器資料並返回結果,資料庫也讀取不到資料則直接返回null。
2. 問題和解決方案
(一)快取穿透
快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷髮起請求,很可能是惡意攻擊,會導致資料庫壓力過大。
解決方案:
1. 在介面層增加校驗,id小於等於0直接攔截,不訪問伺服器。
2. 從快取和資料庫中均讀不到的資料,將redis資料庫中的對應key值設為null,將過期時間設定30秒左右,這樣再次訪問時將直接訪問redis中的null值。但是如果隨機id攻擊,會造成redis伺服器壓力過大,這時可以通過其他模組識別惡意ip地址防止。
3. 使用布隆過濾器過濾資料庫沒有儲存的id,由於布隆過濾器使用bit陣列,擁有佔用記憶體小,運算速度快的特點,所以效率犧牲較小,但是因為布隆過濾器過濾時有可能存在的特性,可能會造成攔截不完全的情況,不過足夠正常業務使用。
(二)快取擊穿
快取擊穿是指快取中沒有但是資料庫中的有的熱點資料,由於併發訪問使用者過多,同時向資料庫查詢,導致壓力瞬間增大,造成資料庫壓力過大。
解決方案:
1. 設定熱點資料永不過期。
2. 加入互斥鎖,當一個執行緒讀取快取資料無資料時,獲取鎖成功後再去資料庫取資料,取完資料後快取到redis伺服器並釋放鎖,這樣另一個執行緒獲取快取無資料時獲取不到鎖,等待一段時間後再嘗試獲取快取資料即可。
示例:
static Lock reenLock = new ReentrantLock(); public String getDate(String key) throws InterruptedException{ //讀取快取伺服器資料 String result = getDataFromRedis(key); if (result == null){ //獲取鎖 if (reenLock.tryLock()){ try { //讀取資料庫伺服器資料 result = getDataFromMysql(key); //正常返回數值,是null就返回null setDataToCache(key,result); } catch (Exception e) { e.printStackTrace(); } finally { //關閉鎖 reenLock.unlock(); } }else { //獲取鎖失敗則等待並重試 Thread.sleep(100); result = getDate(key); } } return result; }
(三)快取雪崩
快取雪崩是指快取中大量熱點資料過期,大量執行緒湧入資料庫,造成資料庫壓力過大或down機。
解決方案:
1. 將快取資料的過期時間設定隨機,防止同一時間大量資料過期。
2. 使用分散式快取資料庫,可以將熱點資料分佈在不同的快取資料庫中。
3. 設定熱點資料永不過期。
(四)資料一致性
當資料庫資料更新時,快取資料庫在同步的過程中可能會產生資料不一致的情況。
解決方案:
1. 使用延時雙刪,先刪除快取伺服器資料,再刪除資料庫伺服器,等待一段時間後再刪除快取伺服器資料,這種方法在大部分情況下都可以滿足業務需求。