1. 程式人生 > 實用技巧 >Redis——實戰問題彙總

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. 使用延時雙刪,先刪除快取伺服器資料,再刪除資料庫伺服器,等待一段時間後再刪除快取伺服器資料,這種方法在大部分情況下都可以滿足業務需求。