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

緩存一致性策略以及雪崩、穿透問題

存儲 存儲軟件
高并發(fā)情境下首先考慮到的第一層優(yōu)化方案就是增加緩存,尤其是通過Redis將原本在數(shù)據(jù)庫中的數(shù)據(jù)復(fù)制一份放到內(nèi)存中,可以減少對數(shù)據(jù)庫的讀操作,數(shù)據(jù)庫的壓力降低,同時(shí)也會加快系統(tǒng)的響應(yīng)速度,但是同樣的也會帶來其他的問題,比如需要考慮數(shù)據(jù)的一致性、還需要預(yù)防可能的緩存擊穿、穿透和雪崩問題等等。

 一. 緩存原理

高并發(fā)情境下首先考慮到的第一層優(yōu)化方案就是增加緩存,尤其是通過Redis將原本在數(shù)據(jù)庫中的數(shù)據(jù)復(fù)制一份放到內(nèi)存中,可以減少對數(shù)據(jù)庫的讀操作,數(shù)據(jù)庫的壓力降低,同時(shí)也會加快系統(tǒng)的響應(yīng)速度,但是同樣的也會帶來其他的問題,比如需要考慮數(shù)據(jù)的一致性、還需要預(yù)防可能的緩存擊穿、穿透和雪崩問題等等。

[[260641]]

1. 實(shí)現(xiàn)步驟

先查詢緩存中有沒有要的數(shù)據(jù),如果有,就直接返回緩存中的數(shù)據(jù)。如果緩存中沒有要的數(shù)據(jù),才去查詢數(shù)據(jù)庫,將得到數(shù)據(jù)更新到緩存再返回,如果數(shù)據(jù)庫中也沒有就可以返回空。

 

考慮數(shù)據(jù)一致性,緩存處的代碼邏輯都較為標(biāo)準(zhǔn)化,首先取Redis,擊中則返回,未擊中則通過數(shù)據(jù)庫來進(jìn)行查詢和同步。

  1. public Result query(String id) { 
  2. Result result = null
  3. //1.從Redis緩存中取數(shù)據(jù) 
  4. result = (Result)redisTemplate.opsForValue().get(id); 
  5. if (null != result){ 
  6. System.out.println("緩存中得到數(shù)據(jù)"); 
  7. return result; 
  8. //2.通過DB查詢,有則同步更新redis,否則返回空 
  9. System.out.println("數(shù)據(jù)庫中得到數(shù)據(jù)"); 
  10. result = Dao.query(id); 
  11. if (null != result){ 
  12. redisTemplate.opsForValue().set(id,result); 
  13. redisTemplate.expire(id,20000, TimeUnit.MILLISECONDS); 
  14. return result; 

其他的新增、刪除和更新操作,可以直接采用先清空該Key下的緩存值再進(jìn)行DB操作,這樣邏輯清晰簡單,維護(hù)的復(fù)雜度會降低,而付出代價(jià)就是多查詢一次。

  1. public void update(Entity entity) { 
  2. redisTemplate.delete(entity.getId()); 
  3. Dao.update(entity); 
  4. return entity; 
  5.  
  6. public Entity add(Entity entity) { 
  7. redisTemplate.delete(entity.getId()); 
  8. Dao.insert(entity); 
  9. return entity; 

2. 緩存更新策略

適用于做緩存的場景一般都是:訪問頻繁、讀場景較多而寫場景少、對數(shù)據(jù)一致性要求不高。如果上面三個(gè)條件都不符合,那維護(hù)一套緩存數(shù)據(jù)的意義并不大了,實(shí)際應(yīng)用中通常都需要針對業(yè)務(wù)場景來選擇合適的緩存方案,下面給出了四種緩存策略,由上到下就是按照一致性由強(qiáng)到弱的順序。

更新策略特點(diǎn)適用場景

實(shí)時(shí)更新同步更新保證強(qiáng)一致性,與業(yè)務(wù)強(qiáng)侵入強(qiáng)耦合金融轉(zhuǎn)賬業(yè)務(wù)等

弱實(shí)時(shí)異步更新(MQ/發(fā)布訂閱/觀察者模式),業(yè)務(wù)解耦,弱一致性存在延遲不適合寫頻繁場景

失效機(jī)制設(shè)置緩存失效,有一定延遲,可能存在雪崩適用讀多寫少,能接受一定的延時(shí)

任務(wù)調(diào)度通過定時(shí)任務(wù)進(jìn)行全量更新統(tǒng)計(jì)類業(yè)務(wù),訪問頻繁且定期更新

二. 緩存雪崩和擊穿

1. 緩存雪崩概念

緩存雪崩是指在我們設(shè)置緩存時(shí)采用了相同的過期時(shí)間,導(dǎo)致緩存在某一時(shí)刻同時(shí)失效,請求全部轉(zhuǎn)發(fā)到DB,DB瞬時(shí)壓力過重雪崩。和緩存擊穿不同的是,緩存擊穿指并發(fā)查同一條數(shù)據(jù),緩存雪崩是不同數(shù)據(jù)都過期了,很多數(shù)據(jù)都查不到從而查數(shù)據(jù)庫。

解決方案

將緩存失效時(shí)間分散開,比如我們可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值,比如1-5分鐘隨機(jī),這樣每一個(gè)緩存的過期時(shí)間的重復(fù)率就會降低,就很難引發(fā)集體失效的事件。

用加鎖或者隊(duì)列的方式保證緩存的單線程(進(jìn)程)寫,從而避免失效時(shí)大量的并發(fā)請求落到底層存儲系統(tǒng)上。

第一種方案比較容易實(shí)現(xiàn),第二種的思路主要是從加阻塞式的排它鎖來實(shí)現(xiàn),在緩存查詢不到的情況下,每此只允許一個(gè)線程去查詢DB,這樣可避免同一個(gè)ID的大量并發(fā)請求都落到數(shù)據(jù)庫中。

  1. public Result query(String id) { 
  2. // 1.從緩存中取數(shù)據(jù) 
  3. Result result = null
  4. result = (Result)redisTemplate.opsForValue().get(id); 
  5. if (result ! = null) { 
  6. logger.info("緩存中得到數(shù)據(jù)"); 
  7. return result; 
  8.  
  9. //2.加鎖排隊(duì),阻塞式鎖 
  10. doLock(id);//多少個(gè)id就可能有多少把鎖 
  11. try{ 
  12. //一次只有一個(gè)線程 
  13. //雙重校驗(yàn),第一次獲取到后面的都可以從緩存中直接擊中 
  14. result = (Result)redisTemplate.opsForValue().get(id); 
  15. if (result != null) { 
  16. logger.info("緩存中得到數(shù)據(jù)"); 
  17. return result;//第二個(gè)線程,這里返回 
  18.  
  19. result = dao.query(id); 
  20. // 3.從數(shù)據(jù)庫查詢的結(jié)果不為空,則把數(shù)據(jù)放入緩存中,方便下次查詢 
  21. if (null != result) { 
  22. redisTemplate.opsForValue().set(id,result); 
  23. redisTemplate.expire(id,20000, TimeUnit.MILLISECONDS); 
  24. return provinces; 
  25. } catch(Exception e) { 
  26. return null
  27. } finally { 
  28. //4.解鎖 
  29. releaseLock(provinceid); 
  30.  
  31. private void releaseLock(String userCode) { 
  32. ReentrantLock oldLock = (ReentrantLock) locks.get(userCode); 
  33. if(oldLock !=null && oldLock.isHeldByCurrentThread()){ 
  34. oldLock.unlock(); 
  35.  
  36. private void doLock(String lockcode) { 
  37. //id有不同的值 
  38. //id相同的,加一個(gè)鎖,不是同一個(gè)key,不能用同一個(gè)鎖 
  39. ReentrantLock newLock = new ReentrantLock();//創(chuàng)建一個(gè)鎖 
  40. //若已存在,則newLock直接丟棄 
  41. Lock oldLock = locks.putIfAbsent(lockcode, newLock); 
  42. if(oldLock == null){ 
  43. newLock.lock(); 
  44. }else
  45. oldLock.lock(); 
  46. ?? 

注意:加鎖排隊(duì)的解決方式在處理分布式環(huán)境的并發(fā)問題,有可能還要解決分布式鎖的問題;線程還會被阻塞,用戶體驗(yàn)很差!因此,在真正的高并發(fā)場景下很少使用!

2. 緩存擊穿概念

一個(gè)存在的key,在緩存過期的一刻,同時(shí)有大量的請求,這些請求都會擊穿到DB,造成瞬時(shí)DB請求量大、壓力驟增。

解決方案

在訪問key之前,采用SETNX(set if not exists)來設(shè)置另一個(gè)短期key來鎖住當(dāng)前key的訪問,訪問結(jié)束再刪除該短期key。

三. 緩存穿透

1. 緩存穿透概念

緩存穿透是指緩存和數(shù)據(jù)庫中都沒有的數(shù)據(jù),而用戶不斷發(fā)起請求,如發(fā)起為id為“-1”的數(shù)據(jù)或id為特別大不存在的數(shù)據(jù)。這時(shí)的用戶很可能遭遇安全威脅,導(dǎo)致數(shù)據(jù)庫壓力過大。

解決方案:布隆過濾器

布隆過濾器的使用方法,類似java的SET集合,用來判斷某個(gè)元素(key)是否在某個(gè)集合中。和一般的hash set不同的是,這個(gè)算法無需存儲key的值,對于每個(gè)key,只需要k個(gè)比特位,每個(gè)存儲一個(gè)標(biāo)志,用來判斷key是否在集合中。

使用步驟:

將List數(shù)據(jù)裝載入布隆過濾器中

  1. private BloomFilter<String> bf =null
  2.  
  3. //PostConstruct注解對象創(chuàng)建后,自動調(diào)用本方法 
  4. @PostConstruct 
  5. public void init(){ 
  6. //在bean初始化完成后,實(shí)例化bloomFilter,并加載數(shù)據(jù) 
  7. List<Entity> entities= initList(); 
  8. //初始化布隆過濾器 
  9. bf = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), entities.size()); 
  10. for (Entity entity : entities) { 
  11. bf.put(entity.getId()); 
  12. ?? 

訪問經(jīng)過布隆過濾器,存在才可以往db中查詢

  1. public Provinces query(String id) { 
  2. //先判斷布隆過濾器中是否存在該值,值存在才允許訪問緩存和數(shù)據(jù)庫 
  3. if(!bf.mightContain(id)) { 
  4. Log.info("非法訪問"+System.currentTimeMillis()); 
  5. return null
  6. Log.info("數(shù)據(jù)庫中得到數(shù)據(jù)"+System.currentTimeMillis()); 
  7. Entity entity= super.query(id); 
  8. return entity; 

這樣當(dāng)外界有惡意威脅時(shí),不存在的數(shù)據(jù)請求就可以直接攔截在過濾器層,而不會影響到底層數(shù)據(jù)庫系統(tǒng)。

責(zé)任編輯:武曉燕 來源: 零壹技術(shù)棧
相關(guān)推薦

2019-02-13 11:04:42

系統(tǒng)緩存軟件

2022-12-14 08:23:30

2020-05-12 10:43:22

Redis緩存數(shù)據(jù)庫

2020-06-01 22:09:48

緩存緩存同步緩存誤用

2024-04-11 13:45:14

Redis數(shù)據(jù)庫緩存

2023-04-13 08:15:47

Redis緩存一致性

2023-08-15 09:31:01

分布式緩存

2017-07-25 14:38:56

數(shù)據(jù)庫一致性非鎖定讀一致性鎖定讀

2023-06-26 07:17:48

負(fù)載均衡策略Dubbo

2024-12-26 15:01:29

2024-11-14 07:10:00

2022-09-06 15:30:20

緩存一致性

2023-08-14 08:10:33

CPU緩存RFO

2021-06-11 09:21:58

緩存數(shù)據(jù)庫Redis

2021-02-05 08:00:48

哈希算法?機(jī)器

2021-02-02 12:40:50

哈希算法數(shù)據(jù)

2023-05-09 10:59:33

緩存技術(shù)派MySQL

2024-04-23 08:22:58

Meta緩存系統(tǒng)

2024-05-28 00:50:00

RedisMySQL緩存

2024-10-28 12:41:25

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號