日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

更多內容,歡迎關注微信公眾號:全菜工程師小輝~

緩存穿透

緩存系統,一般流程都是按照key去查詢緩存,如果不存在對應的value,就去后端系統(例如:持久層數據庫)查找。如果key對應的value是一定不存在的,并且對該key并發請求量很大,就會對后端系統造成很大的壓力,這就叫做緩存穿透。

正常請求:

快速了解緩存穿透與緩存雪崩

 

正常請求

緩存擊穿時:

快速了解緩存穿透與緩存雪崩

 

緩存擊穿

如何避免

1. 緩存空結果

對查詢結果為空的情況進行緩存,緩存時間設置短一點,或者該key對應的數據insert了之后清理緩存。

2. 布隆過濾器

采用布隆過濾器,guava有實現api,或者使用redis的bitmap。將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。布隆過濾器對于固定的數據可以起到很好的效果,但是對于頻繁更新的數據,布隆過濾器的構建會面臨很多問題。另外布隆過濾器是有判斷誤差的,網上有很多詳細的介紹,請讀者自行搜索即可。

快速了解緩存穿透與緩存雪崩

 

布隆過濾器

緩存雪崩

當緩存服務器重啟或者大量緩存集中在某一個時間段失效,這樣在失效的時候,也會給后端系統(比如DB)帶來很大壓力。

如何避免

1. 互斥鎖

在緩存失效后,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。

快速了解緩存穿透與緩存雪崩

 

互斥鎖

如果是單機,可以用synchronized或者lock來處理,如果是分布式環境就需要使用分布式鎖。

使用互斥鎖,代碼如下,僅適用redis2.6.1以后支持setnx的版本。在緩存失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用redis的setnx操作去set一個mutex key。當操作返回成功時,再進行load db的操作并回設緩存,否則,就重試整個get緩存的方法。

快速了解緩存穿透與緩存雪崩

 

互斥鎖

public String get(key) {
 List<String> resultList = (List<String>)redisTemplate.opsForValue().get(key);
 if(CollectionUtils.isEmpty(resultList)){
 final String mutexKey = key + "_lock";
 boolean isLock = (Boolean) redisTemplate.execute(new RedisCallback() {
 @Override
 public Object doInRedis(RedisConnection connection) throws DataAccessException {
 //只在鍵key不存在的情況下,將鍵key的值設置為value,若鍵key已經存在,則 SETNX 命令不做任何動作
 //命令在設置成功時返回 1 , 設置失敗時返回 0
 return connection.setNX(mutexKey.getBytes(),"1".getBytes());
 }
 });
 if(isLock){
 //設置成1秒過期
 redisTemplate.expire(mutexKey, 1000, TimeUnit.MILLISECONDS);
 resultList = getValueBySql(key);
 redisTemplate.opsForValue().set(key, resultList, 1000, TimeUnit.SECONDS);
 redisTemplate.delete(mutexKey);
 }else{
 //線程休息50毫秒后重試
 Thread.sleep(50);
 retryCount--;
 System.out.println("=====進行重試,當前次數:" + retryCount);
 if(retryCount == 0){
 System.out.println("====這里發郵件或者記錄下獲取不到數據的日志,并為key設置一個空置防止重復獲取");
 List<String> list = Lists.newArrayList("no find");
 redisTemplate.opsForValue().set(key, list, 1000, TimeUnit.SECONDS);
 return list;
 }
 return getCacheSave2(key,retryCount);
 }
 }
 return resultList;
}

2. 設置隨機過期時間

不同的key,設置不同的過期時間,讓緩存失效時間分散開,比如可以在原有的失效時間基礎上增加一個隨機值,比如1-5分鐘隨機,這樣每一個緩存的過期時間的重復率就會降低。

3. 設置二級緩存

做二級緩存,A1為原始緩存,A2為拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置為短期,A2設置為長期

4. “永遠不過期”

“永遠不過期”包含兩層意思:

  1. 從redis上看,確實沒有設置過期時間,這就保證了,不會出現熱點key過期問題,也就是“物理”不過期。
  2. 從功能上看,把過期時間存在key對應的value里,如果發現要過期了,通過一個后臺的異步線程進行緩存的構建,也就是“邏輯”過期。

 

快速了解緩存穿透與緩存雪崩

 

“永遠不過期”

這種方法對于性能非常友好,唯一不足的就是構建緩存時候,其余線程(非構建緩存的線程)可能訪問的是老數據,但是對于一般的互聯網功能來說這個還是可以忍受。

緩存預熱

有效應對緩存的擊穿和雪崩的一種方式是緩存預熱。

緩存預熱就是系統上線前,將相關的緩存數據直接加載到緩存系統。這樣就可以避免在用戶請求的時候,先查詢數據庫,然后再將數據緩存的問題,用戶直接查詢事先被預熱的緩存數據。

解決思路

  1. 直接寫個緩存刷新頁面,上線時手工操作下。
  2. 數據量不大,可以在項目啟動的時候自動進行加載。
  3. 定時刷新緩存。

限流

有效應對緩存的擊穿和雪崩的另一種方式是限流。

在緩存失效后,通過隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。

常見的限流算法

  1. 固定時間窗口算法(計數器)
  2. 滑動時間窗口算法
  3. 令牌桶算法
  4. 漏桶算法

有關限流算法的詳細介紹,請點擊查看高并發系統的限流算法與實現

總結

緩存穿透、擊穿和雪崩是以預防為主、補救為輔,而在應對緩存的問題其實也沒有一個完全完美的方案,只有最適合自己業務系統的方案。

更多內容,歡迎關注微信公眾號:全菜工程師小輝~

分享到:
標簽:緩存 穿透
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定