掃二維碼與項目經理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網交流
「Redis 是一個開源(BSD許可)的,內存中的數(shù)據(jù)結構存儲系統(tǒng),它可以用作數(shù)據(jù)庫、緩存和消息中間件?!?/p>

創(chuàng)新互聯(lián)網站建設由有經驗的網站設計師、開發(fā)人員和項目經理組成的專業(yè)建站團隊,負責網站視覺設計、用戶體驗優(yōu)化、交互設計和前端開發(fā)等方面的工作,以確保網站外觀精美、成都網站建設、成都網站制作易于使用并且具有良好的響應性。
Redis在緩存應用中還是很廣泛的,項目中也經常使用?;旧厦嬖囍锌隙ǘ紩柕?,總結一下增強記憶哈!
在享受緩存帶來的好處的同時,當然要防止這些不好的方面。
下面我們一起來看看這三種情況的產生原因和解決方案!
「總結: 這三種情況都是在大量請求來的時候,Redis沒有命中,請求直接打到數(shù)據(jù)庫,從而導致數(shù)據(jù)庫掛掉!」
Redis緩存簡圖:
「大量請求的 key 是不合理的,緩存中根本不存在(數(shù)據(jù)庫中一般也不存在),導致這些請求繞過緩存直接訪問數(shù)據(jù)庫,給數(shù)據(jù)庫造成了巨大的壓力,隨時可能宕機?!?/p>
redis有一個配置,可以把從數(shù)據(jù)庫查詢出來為空的也緩存到Redis中,也可以自己在代碼中寫,順便加上過期時間,也可以配置過期時間,這樣是全局都是這個過期時間了,不太建議這樣!
spring:
cache:
redis:
cache-null-value: true
time-to-live: 30s@Cacheable(value={"category"},key = "#root.methodName",sync = true)
sync = true:表示多個線程在嘗試獲取緩存數(shù)據(jù)的時候會被阻塞,直到第一個線程從數(shù)據(jù)庫加載數(shù)據(jù)并放入緩存后,其他線程才能獲取到緩存中的數(shù)據(jù)。這樣可以避免多個線程同時查詢底層數(shù)據(jù)庫,減輕數(shù)據(jù)庫負載,但會降低并發(fā)性能。 默認為false,不開啟
布隆過濾器(Bloom Filter)是一種用于判斷一個元素是否屬于一個集合的數(shù)據(jù)結構。它的主要特點是高效地判斷元素是否存在于集合中,且具有空間和時間效率高的優(yōu)點。布隆過濾器不會存儲實際的數(shù)據(jù),而是通過一系列的哈希函數(shù)和位數(shù)組來判斷元素的存在。
「當布隆過濾器判斷元素不存在時,元素一定不存在,元素存在時,元素不一定存在!」
是不是有點繞,我們在詳細說一下:
布隆過濾器有一定的假陽性概率,即在判斷元素存在時,有可能出現(xiàn)錯誤的結果。這是因為多個元素可能產生相同的哈希值,導致位數(shù)組中的位被設置為1。
「布隆過濾器一旦添加了元素,就不能刪除,因為刪除元素會影響其他元素的判斷結果?!?/p>
一般引入guava中的BloomFilter來實現(xiàn)布隆過濾器!如果喜歡用Hutool,也是有實現(xiàn)的!
下面小編給大家簡單的寫個demo,大家感受一下!
com.google.guava
guava
30.1-jre
/**
* @author wangzhenjun
* @date 2023/11/7 17:08
*/
@Configuration
public class BloomFilterConfig {
// 預期插入的元素個數(shù),從配置文件里拿
private static final Integer EXPECTED_INSERTIONS = 100000;
// 期望的誤判率,值越低,布隆過濾器計算時間越長,從配置文件里拿
private static final Double FPP = 0.03;
@Bean
public BloomFilter bloomFilter(){
BloomFilter filter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")), EXPECTED_INSERTIONS,FPP);
return filter;
}
} 為了簡單,直接寫在啟動類上了,大家不要學哈!
@EnableAsync
@MapperScan("com.example.demonew.demo.mapper")
@EnableTransactionManagement
@SpringBootApplication
public class DemoNewApplication {
@Autowired
private BloomFilter bloomFilter;
public static void main(String[] args) {
SpringApplication.run(DemoNewApplication.class, args);
}
@PostConstruct
public void init(){
bloomFilter.put("123");
boolean b = bloomFilter.mightContain("123");
System.out.println("是否存在:" + b);
}
}
「緩存擊穿是指當緩存中某個熱點key剛剛過期(一般和緩存穿透區(qū)別在于熱點數(shù)據(jù)存在于數(shù)據(jù)庫中),在熱點數(shù)據(jù)重新放入緩存之前,瞬間大量的請求繞過緩存,直接打到數(shù)據(jù)庫,數(shù)據(jù)庫隨時宕機!」
并發(fā)訪問熱點key:多個并發(fā)請求同時訪問相同的緩存鍵
緩存策略問題:設置了過于短的緩存過期時間,容易導致緩存頻繁失效。
「一般出現(xiàn)在秒殺中,秒殺都會提前預熱,設置key直到活動結束才會過期!」
在項目啟動時,或者定時任務掃描進行預熱!
@Cacheable(value={"category"},key = "#root.methodName",sync = true)、
詳細解釋上面已經說過了哈!
可以引入:Sentinel來幫助我們更好的限流、熔斷、降級,這里就不詳細演示了!
其實緩存擊穿和緩存雪崩是很相似的,解決方案,大家也可以看出來很多相同的!這就引出下一個經常問到的問題:
關于Redis的哨兵搭建可以看一下之前寫的文章,這里就不演示了!
關于多級緩存,可以引入本地緩存Caffeine。
緩存擊穿是緩存中某個熱點key不存在了,緩存雪崩是緩存中大量或者所有key都不存在了
他倆的根本區(qū)別在于一個是單個key,一個是多個甚至全部key!
這里補充一下,關于緩存污染的吧!
緩存污染指緩存中一些訪問次數(shù)很少的key,甚至只有一次!但是緩存中會存儲著,占用內存空間。隨著時間越來越久,內存很快被占滿,就需要開啟淘汰策略去額外處理這些多余的key,影響redis性能。
最主要還是要把不常用的key找到,后面不在加入緩存,從根本上解決!
還會出現(xiàn)在多個節(jié)點之間的數(shù)據(jù)同步出現(xiàn)數(shù)據(jù)不統(tǒng)一時產生,這個東西不好避免,因為Redis 是AP(可用性和分區(qū)容忍性),在多節(jié)點時,一半以上同步完成時,就認為同步成功了!
引入了緩存就必須要保持緩存的一致性,不然加了緩存沒有任何意義!
網上關于緩存一致性的文章很多,什么延遲雙刪等等。
這些都不如阿里Canal,這個是通過監(jiān)聽MySQL的Bin Log日志,來去更新到緩存中!
今天我們深入具體的討論了Redis緩存穿透、緩存擊穿、緩存雪崩的產生原因和解決方案,補充了緩存污染和緩存一致性。
是不是有了深刻的印象,這些東西在企業(yè)級還是挺常見的,在面試過程中更加常見。 相信大家從頭看到尾,對于面試肯定是沒有任何問題的。
在企業(yè)級應用中,一定要具體情況具體分析,不要盲目照搬,不一定適合你們的需求。

我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網交流