首頁 > 軟體

Redis安全策略詳解

2022-07-27 22:07:24

快取穿透

高並行情況下查詢一個不存在的key

產生的背景(原因):

快取穿透是指使用不存在的key進行大量的高並行查詢,導致快取無法命中,每次請求都要都要穿透到後端資料庫查詢,使得資料庫的壓力非常大,甚至導致資料庫服務壓死;

解決方案:

  1. 介面層實現api限流、使用者授權、id檢查等;
  2. 從快取和資料庫都取不到資料的話,一樣將資料庫空值放入快取中,設定30s有效期避免使用同一個id對資料庫攻擊壓力大;
  3. 布隆過濾器

快取擊穿

高並行情況下查詢的一個key突然過期

產生背景(原因):

在高並行的情況下,當一個快取key過期時,因為存取該key請求較大,多個請求同時發現快取過期,因此對多個請求同時資料庫查詢、同時向Redis寫入快取資料,這樣會導致資料庫的壓力非常大;

解決方案:

  1. 使用分散式鎖

保證在分散式情況下,使用分散式鎖保證對於每個key同時只允許只有一個執行緒查詢到後端服務,其他沒有獲取到鎖的許可權,只需要等待即可;這種高並行壓力直接轉移到分散式鎖上,對分散式鎖的壓力非常大。

  1. 使用本地鎖

使用本地鎖與分散式鎖機制一樣,只不過分散式鎖適應於服務叢集、本地鎖僅限於單個服務使用。

  1. 軟過過期

設定熱點資料永不過期或者非同步延長過期時間;

快取雪崩

高並行情況下大量的key 集中失效

產生背景(原因):

快取雪崩指快取伺服器重啟或者大量的快取集中在某個時間段失效,突然給資料庫產生了巨大的壓力,甚至擊垮資料庫的情況。

解決思路:對不用的資料使用不同的失效時間,加上亂數

布隆過濾器

布隆過濾器適用於判斷某個資料是否在集合中存在,不一定百分百準備, Bloom Filter基本實現原理採用位陣列與聯合函數一起實現;

布隆過濾器最大的問題:就是可能會存在一個誤判的問題,如果向誤判概率越低,則二進位制陣列會越大,同時也會非常佔用空間

基於布隆過濾器解決快取穿透問題

maven依賴

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>22.0</version>
</dependency>

測試程式碼

public class BlongTest {
    /**
     * 在布隆中存放100萬條資料
     */
    private static Integer size = 1000000;
    public static void main(String[] args) {
        BloomFilter<Integer> integerBloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, 0.01);
        for (int i = 0; i < size; i++) {
            integerBloomFilter.put(i);
        }
        // 從布隆中查詢資料是否存在
        ArrayList<Integer> strings = new ArrayList<>();
        for (int j = size; j < size + 10000; j++) {
            if (integerBloomFilter.mightContain(j)) {
                strings.add(j);
            }
        }
        System.out.println("誤判數量:" + strings.size());
    }
}

解決快取擊穿程式碼

@RequestMapping("/getOrder")
public OrderEntity getOrder(Integer orderId) {
    if (integerBloomFilter != null) {
        if (!integerBloomFilter.mightContain(orderId)) {
            System.out.println("從布隆過濾器中檢測到該key不存在");
            return null;
        }
    }
    // 1.先查詢Redis中資料是否存在
    OrderEntity orderRedisEntity = (OrderEntity) redisTemplateUtils.getObject(orderId + "");
    if (orderRedisEntity != null) {
        System.out.println("直接從Redis中返回資料");
        return orderRedisEntity;
    }
    // 2. 查詢資料庫的內容
    System.out.println("從DB查詢資料");
    OrderEntity orderDBEntity = orderMapper.getOrderById(orderId);
    if (orderDBEntity != null) {
        System.out.println("將Db資料放入到Redis中");
        redisTemplateUtils.setObject(orderId + "", orderDBEntity);
    }
    return orderDBEntity;
}
/**
* 新增訂單id到布隆過濾器中
*/
@RequestMapping("/dbToBulong")
public String dbToBulong() {
    List<Integer> orderIds = orderMapper.getOrderIds();
    integerBloomFilter = BloomFilter.create(Funnels.integerFunnel(), orderIds.size(), 0.01);
    for (int i = 0; i < orderIds.size(); i++) {
        integerBloomFilter.put(orderIds.get(i));
    }
    return "success";
}

到此這篇關於Redis安全策略詳解的文章就介紹到這了,更多相關Redis安全內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com