Redis安全策略詳解
緩存穿透
高并發(fā)情況下查詢一個(gè)不存在的key
產(chǎn)生的背景(原因):
緩存穿透是指使用不存在的key進(jìn)行大量的高并發(fā)查詢,導(dǎo)致緩存無(wú)法命中,每次請(qǐng)求都要都要穿透到后端數(shù)據(jù)庫(kù)查詢,使得數(shù)據(jù)庫(kù)的壓力非常大,甚至導(dǎo)致數(shù)據(jù)庫(kù)服務(wù)壓死;
解決方案:
- 接口層實(shí)現(xiàn)api限流、用戶授權(quán)、id檢查等;
- 從緩存和數(shù)據(jù)庫(kù)都取不到數(shù)據(jù)的話,一樣將數(shù)據(jù)庫(kù)空值放入緩存中,設(shè)置30s有效期避免使用同一個(gè)id對(duì)數(shù)據(jù)庫(kù)攻擊壓力大;
- 布隆過(guò)濾器
緩存擊穿
高并發(fā)情況下查詢的一個(gè)key突然過(guò)期
產(chǎn)生背景(原因):
在高并發(fā)的情況下,當(dāng)一個(gè)緩存key過(guò)期時(shí),因?yàn)樵L問(wèn)該key請(qǐng)求較大,多個(gè)請(qǐng)求同時(shí)發(fā)現(xiàn)緩存過(guò)期,因此對(duì)多個(gè)請(qǐng)求同時(shí)數(shù)據(jù)庫(kù)查詢、同時(shí)向Redis寫(xiě)入緩存數(shù)據(jù),這樣會(huì)導(dǎo)致數(shù)據(jù)庫(kù)的壓力非常大;
解決方案:
- 使用分布式鎖
保證在分布式情況下,使用分布式鎖保證對(duì)于每個(gè)key同時(shí)只允許只有一個(gè)線程查詢到后端服務(wù),其他沒(méi)有獲取到鎖的權(quán)限,只需要等待即可;這種高并發(fā)壓力直接轉(zhuǎn)移到分布式鎖上,對(duì)分布式鎖的壓力非常大。
- 使用本地鎖
使用本地鎖與分布式鎖機(jī)制一樣,只不過(guò)分布式鎖適應(yīng)于服務(wù)集群、本地鎖僅限于單個(gè)服務(wù)使用。
- 軟過(guò)過(guò)期
設(shè)置熱點(diǎn)數(shù)據(jù)永不過(guò)期或者異步延長(zhǎng)過(guò)期時(shí)間;
緩存雪崩
高并發(fā)情況下大量的key 集中失效
產(chǎn)生背景(原因):
緩存雪崩指緩存服務(wù)器重啟或者大量的緩存集中在某個(gè)時(shí)間段失效,突然給數(shù)據(jù)庫(kù)產(chǎn)生了巨大的壓力,甚至擊垮數(shù)據(jù)庫(kù)的情況。
解決思路:對(duì)不用的數(shù)據(jù)使用不同的失效時(shí)間,加上隨機(jī)數(shù)
布隆過(guò)濾器
布隆過(guò)濾器適用于判斷某個(gè)數(shù)據(jù)是否在集合中存在,不一定百分百準(zhǔn)備, Bloom Filter基本實(shí)現(xiàn)原理采用位數(shù)組與聯(lián)合函數(shù)一起實(shí)現(xiàn);
布隆過(guò)濾器最大的問(wèn)題:就是可能會(huì)存在一個(gè)誤判的問(wèn)題,如果向誤判概率越低,則二進(jìn)制數(shù)組會(huì)越大,同時(shí)也會(huì)非常占用空間
基于布隆過(guò)濾器解決緩存穿透問(wèn)題
maven依賴
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>22.0</version> </dependency>
測(cè)試代碼
public class BlongTest { /** * 在布隆中存放100萬(wàn)條數(shù)據(jù) */ 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); } // 從布隆中查詢數(shù)據(jù)是否存在 ArrayList<Integer> strings = new ArrayList<>(); for (int j = size; j < size + 10000; j++) { if (integerBloomFilter.mightContain(j)) { strings.add(j); } } System.out.println("誤判數(shù)量:" + strings.size()); } }
解決緩存擊穿代碼
@RequestMapping("/getOrder") public OrderEntity getOrder(Integer orderId) { if (integerBloomFilter != null) { if (!integerBloomFilter.mightContain(orderId)) { System.out.println("從布隆過(guò)濾器中檢測(cè)到該key不存在"); return null; } } // 1.先查詢Redis中數(shù)據(jù)是否存在 OrderEntity orderRedisEntity = (OrderEntity) redisTemplateUtils.getObject(orderId + ""); if (orderRedisEntity != null) { System.out.println("直接從Redis中返回?cái)?shù)據(jù)"); return orderRedisEntity; } // 2. 查詢數(shù)據(jù)庫(kù)的內(nèi)容 System.out.println("從DB查詢數(shù)據(jù)"); OrderEntity orderDBEntity = orderMapper.getOrderById(orderId); if (orderDBEntity != null) { System.out.println("將Db數(shù)據(jù)放入到Redis中"); redisTemplateUtils.setObject(orderId + "", orderDBEntity); } return orderDBEntity; } /** * 添加訂單id到布隆過(guò)濾器中 */ @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"; }
到此這篇關(guān)于Redis安全策略詳解的文章就介紹到這了,更多相關(guān)Redis安全內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
CentOS 7下安裝 redis 3.0.6并配置集群的過(guò)程詳解
這篇文章主要給大家介紹了CentOS 7下安裝 redis 3.0.6并配置集群的過(guò)程,文中通過(guò)示例代碼和詳細(xì)的步驟介紹的很相信,對(duì)大家具有一定的參考價(jià)值,有需要的朋友們下面來(lái)一起看看吧。2017-01-01Redis中實(shí)現(xiàn)查找某個(gè)值的范圍
這篇文章主要介紹了Redis中實(shí)現(xiàn)查找某個(gè)值的范圍,本文的題引來(lái)了Redis作者Salvatore Sanfilippo(@antirez)的回答,比較經(jīng)典,需要的朋友可以參考下2015-06-06Redis中set類(lèi)型實(shí)現(xiàn)交集并集差集
本文主要介紹了Redis中set類(lèi)型實(shí)現(xiàn)交集并集差集,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06