自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

緩存雪崩,緩存穿透,緩存擊穿出現的原因及解決方案?

存儲
假設有如下一個系統(tǒng),高峰期請求為5000次/秒,4000次走了緩存,只有1000次落到了數據庫上,數據庫每秒1000的并發(fā)是一個正常的指標,完全可以正常工作,但如果緩存宕機了,或者緩存設置了相同的過期時間,導致緩存在同一時刻同時失效,每秒5000次的請求會全部落到數據庫上,數據庫立馬就死掉了,因為數據庫一秒最多抗2000個請求,如果DBA重啟數據庫,立馬又會被新的請求打死了,這就是緩存雪崩。

 [[317484]]

緩存雪崩

出現過程

假設有如下一個系統(tǒng),高峰期請求為5000次/秒,4000次走了緩存,只有1000次落到了數據庫上,數據庫每秒1000的并發(fā)是一個正常的指標,完全可以正常工作,但如果緩存宕機了,或者緩存設置了相同的過期時間,導致緩存在同一時刻同時失效,每秒5000次的請求會全部落到數據庫上,數據庫立馬就死掉了,因為數據庫一秒最多抗2000個請求,如果DBA重啟數據庫,立馬又會被新的請求打死了,這就是緩存雪崩。

 

 

 

 

 

解決方法

  1. 事前:redis高可用,主從+哨兵,redis cluster,避免全盤崩潰
  2. 事中:本地ehcache緩存 + hystrix限流&降級,避免MySQL被打死
  3. 事后:redis持久化RDB+AOF,快速恢復緩存數據
  4. 緩存的失效時間設置為隨機值,避免同時失效

緩存穿透

出現過程

假如客戶端每秒發(fā)送5000個請求,其中4000個為黑客的惡意攻擊,即在數據庫中也查不到。舉個例子,用戶id為正數,黑客構造的用戶id為負數,如果黑客每秒一直發(fā)送這4000個請求,緩存就不起作用,數據庫也很快被打死。

 

 

 

 

 

解決方法

  1. 對請求參數進行校驗,不合理直接返回
  2. 查詢不到的數據也放到緩存,value為空,如 set -999 ""
  3. 使用布隆過濾器,快速判斷key是否在數據庫中存在,不存在直接返回

緩存擊穿

出現過程

設置了過期時間的key,承載著高并發(fā),是一種熱點數據。從這個key過期到重新從MySQL加載數據放到緩存的一段時間,大量的請求有可能把數據庫打死。緩存雪崩是指大量緩存失效,緩存擊穿是指熱點數據的緩存失效

解決方法

  1. 設置key永遠不過期,或者快過期時,通過另一個異步線程重新設置key
  2. 當從緩存拿到的數據為null,重新從數據庫加載數據的過程上鎖,下面寫個分布式鎖實現的demo

Redis實現分布式鎖

我之前的文章寫到了Redis實現分布式鎖的原理,這里就不再詳細概述了

在Redis中使用簡單強大的Lua腳本

1.加鎖執(zhí)行命令

 

  1. SET resource_name random_value NX PX 30000 

2.解鎖執(zhí)行腳本

 

  1. if redis.call("get", KEYS[1]) == ARGV[1] then  
  2.     return redis.call("del", KEYS[1])  
  3. else  
  4.     return 0  
  5. end 

寫一個分布式鎖工具類

 

  1. public class LockUtil { 
  2.  
  3.     private static final String OK = "OK"
  4.     private static final Long LONG_ONE = 1L; 
  5.     private static final String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"
  6.  
  7.     public static boolean tryLock(String key, String value, long expire) { 
  8.         Jedis jedis = RedisPool.getJedis(); 
  9.         SetParams setParams = new SetParams(); 
  10.         setParams.nx().px(expire); 
  11.         return OK.equals(jedis.set(key, value, setParams)); 
  12.     } 
  13.  
  14.     public static boolean releaseLock(String key, String value) { 
  15.         Jedis jedis = RedisPool.getJedis(); 
  16.         return LONG_ONE.equals(jedis.eval(script, 1, key, value)); 
  17.     } 

工具類寫起來還是挺簡單的

示例代碼

 

  1. public String getData(String key) { 
  2.     String lockKey = "key"
  3.     String lockValue = String.valueOf(System.currentTimeMillis()); 
  4.     long expireTime = 1000L; 
  5.     String value = getFromRedis(key); 
  6.     if (value == null) { 
  7.         if (LockUtil.tryLock(lockKey, lockValue, expireTime)) { 
  8.             // 從數據庫取值并放到redis中 
  9.             LockUtil.releaseLock(lockKey, lockValue); 
  10.         } else { 
  11.             // sleep一段時間再從緩存中拿 
  12.             Thread.sleep(100); 
  13.             getFromRedis(key); 
  14.         } 
  15.     } 
  16.     return value; 

 

責任編輯:武曉燕 來源: Java識堂
相關推薦

2023-11-10 14:58:03

2023-03-10 13:33:00

緩存穿透緩存擊穿緩存雪崩

2019-10-12 14:19:05

Redis數據庫緩存

2022-03-08 00:07:51

緩存雪崩數據庫

2019-11-05 14:24:31

緩存雪崩框架

2021-06-05 09:01:01

Redis緩存雪崩緩存穿透

2020-03-16 14:57:24

Redis面試雪崩

2022-05-27 07:57:20

緩存穿透緩存雪崩緩存擊穿

2022-11-18 14:34:28

2023-04-14 07:34:19

2023-10-13 08:11:22

2024-03-12 10:44:42

2021-12-25 22:28:27

緩存穿透緩存擊穿緩存雪崩

2020-10-13 07:44:40

緩存雪崩 穿透

2023-12-06 13:38:00

Redis緩存穿透緩存擊穿

2020-10-23 10:46:03

緩存雪崩擊穿

2022-07-11 07:36:36

緩存緩存雪崩緩存擊穿

2020-12-28 12:37:36

緩存擊穿穿透

2023-01-18 07:48:32

緩存穿透緩存擊穿redis

2021-01-31 10:51:37

緩存lock數據
點贊
收藏

51CTO技術棧公眾號