Redis緩存策略超詳細(xì)講解_第1頁
Redis緩存策略超詳細(xì)講解_第2頁
Redis緩存策略超詳細(xì)講解_第3頁
Redis緩存策略超詳細(xì)講解_第4頁
Redis緩存策略超詳細(xì)講解_第5頁
已閱讀5頁,還剩2頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第Redis緩存策略超詳細(xì)講解目錄Redis緩存中間件緩存是什么緩存的優(yōu)點緩存的缺點Redis緩存已查詢數(shù)據(jù)redis緩存中間件實踐緩存更新緩存更新的三個策略主動更新策略的三種方案主動更新的代碼實現(xiàn)

Redis緩存中間件

緩存是什么

所謂緩存就是數(shù)據(jù)交換的緩沖區(qū)(稱作Cache[k?]),是一個臨時存貯數(shù)據(jù)的地方,一般讀寫性能較高。CPU的運算速度要遠(yuǎn)遠(yuǎn)大于內(nèi)存的讀寫速度,這樣會使CPU花費很長時間等待數(shù)據(jù)從內(nèi)存的獲取或者寫入,因此緩存的出現(xiàn)主要就是為了解決CPU運算速度與內(nèi)存讀寫速度不匹配的矛盾

說了半天緩存和web開發(fā)有什么必要的聯(lián)系嘛?當(dāng)然有,在整個web開發(fā)的各個階段都可以使用到不同緩存,比如瀏覽器緩存頁面等靜態(tài)資源,tomcat服務(wù)器應(yīng)用層緩存查詢過的數(shù)據(jù),數(shù)據(jù)庫緩存索引信息等

緩存的優(yōu)點

降低后端負(fù)載提高讀寫效率,降低響應(yīng)時間

緩存的缺點

數(shù)據(jù)更新前后緩存區(qū)中該數(shù)據(jù)的一致性難保證解決數(shù)據(jù)一致性需要復(fù)雜的業(yè)務(wù)代碼,提高后續(xù)維護(hù)成本集群模式下提高運維成本

Redis緩存已查詢數(shù)據(jù)

在未使用緩存之前,用戶的所有請求都會直接訪問數(shù)據(jù)庫,但是使用redis作為緩存之后就不一樣了。用戶的請求會是先在redis中查找,如果查到也就是命中的話就直接返回客戶端,如果未命中的話就去數(shù)據(jù)庫中查找,查到有結(jié)果就將查詢到的結(jié)果寫入redis中,然后返回給客戶端;未查到結(jié)果就返回404狀態(tài)碼

redis緩存中間件實踐

黑馬點評中有這么一個業(yè)務(wù):點擊商鋪圖片會通過id查詢該商鋪的相關(guān)信息,如果使用redis緩存的話,后期再訪問該商鋪的話就會直接到redis中查詢,可以大大縮短查詢所需時間

collector中定義與前端交互的方法,前端請求/shop-type/listid=xx

@RestController

@RequestMapping("/shop")

publicclassShopController{

@Resource

publicIShopServiceshopService;

*根據(jù)id查詢商鋪信息

*@paramid商鋪id

*@return商鋪詳情數(shù)據(jù)

@GetMapping("/{id}")

publicResultqueryShopById(@PathVariable("id")Longid){

returnshopService.queryById(id);

編寫typeService里業(yè)務(wù)邏輯方法getList的接口和實現(xiàn)類,邏輯參考Redis緩存已查詢數(shù)據(jù)的相關(guān)分析

@Service

publicclassShopServiceImplextendsServiceImplShopMapper,ShopimplementsIShopService{

@Autowired

privateStringRedisTemplatestringRedisTemplate;

@Override

publicResultqueryById(Longid){

//從redis查詢商鋪緩存

StringshopJson=stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY+id);

//判斷該商鋪是否存在

if(StrUtil.isNotBlank(shopJson)){

//存在直接返回

Shopshop=JSONUtil.toBean(shopJson,Shop.class);

returnResult.ok(shop);

//不存在查詢數(shù)據(jù)庫

Shopshop=getById(id);

if(shop==null){

//數(shù)據(jù)庫中不存在直接返回錯誤信息

returnResult.fail("店鋪不存在");

//數(shù)據(jù)庫中存在寫入redis

stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY+id,JSONUtil.toJsonStr(shop));

//返回

returnResult.ok(shop);

}

經(jīng)實驗驗證得知,使用redis緩存未命中時查詢耗時將近200毫秒,后續(xù)查詢命中之后只需幾毫秒,可見redis作為緩存中間件對數(shù)據(jù)讀取的功效還是很高的

緩存更新

之前介紹redis的時候介紹過redis緩存的一些缺點,比如數(shù)據(jù)庫中數(shù)據(jù)更新前后緩存區(qū)中該數(shù)據(jù)的一致性難保證,該怎么應(yīng)對redis緩存的這個缺點呢?這就引出接下來的學(xué)習(xí)內(nèi)容緩存更新策略

緩存更新的三個策略

內(nèi)存淘汰:redis底層的內(nèi)存淘汰機制,無需我們自己維護(hù),當(dāng)內(nèi)存不足時自動淘汰部分?jǐn)?shù)據(jù),下次查詢時更新緩存。這種機制的優(yōu)點是維護(hù)成本極低,但是缺點也很明顯,由于淘汰數(shù)據(jù)的不確定性導(dǎo)致很難保證數(shù)據(jù)的一致性

超時剔除:向redis中添加緩存數(shù)據(jù)的時候設(shè)置TTL時間,到期后自動刪除緩存,下次查詢時更新緩存。這種機制維護(hù)成本不是很高,但是數(shù)據(jù)一致性同樣無法做到很高的保證,因為設(shè)置之后數(shù)據(jù)的有效期就固定了,但是更新時間不固定,若是數(shù)據(jù)在超時剔除之前發(fā)生更新然后查詢,得到的仍是更新之前的數(shù)據(jù)

主動更新:使用代碼在修改數(shù)據(jù)庫的同時更新緩存。這種策略能夠保證很高的數(shù)據(jù)一致性,但是伴隨而來的就是更高的維護(hù)成本,要在每一個更改語句后面加上redis緩存更新

具體使用哪種策略取決于該業(yè)務(wù)對數(shù)據(jù)一致性的需求:一致性需求不高的話,可以使用內(nèi)存淘汰策略。一致性需求較高的話,可以使用主動更新加上超時剔除策略,保證了較高的一致性

主動更新策略的三種方案

代碼(CacheAsidePattern):最直接的一種方案,使用代碼在修改數(shù)據(jù)庫的同時更新緩存

服務(wù)(Read/WariteThroughPattern):將redis緩存與數(shù)據(jù)庫整合為一個服務(wù),由這個服務(wù)來維護(hù)數(shù)據(jù)的一致性,在更新數(shù)據(jù)庫時只需要調(diào)用該服務(wù)即可,無需關(guān)心服務(wù)底層的業(yè)務(wù)邏輯,類似于封裝。但是市面上沒有現(xiàn)成的服務(wù)可以使用,自己封裝這么一個服務(wù)也很復(fù)雜,所以說這種方案可用性很差

寫回(WriteBehindCachingPattern):所有數(shù)據(jù)庫的CRUD操作都在redis緩存中完成,由另外一個獨立的線程異步的將緩存中的數(shù)據(jù)持久化到數(shù)據(jù)庫中,以此來保證數(shù)據(jù)的最終一致。這種方案有個很大的好處,那就是極大地減少了對數(shù)據(jù)庫的操作,如果主線程在另一個線程兩次持久化之間對redis中的數(shù)據(jù)操作多次,數(shù)據(jù)庫中只會執(zhí)行最后一次操作,而不是也操作多次。但是也有壞處,那就是如果還沒等到另一個線程持久化數(shù)據(jù)庫,此時redis緩存發(fā)生宕機,緩存大多數(shù)在內(nèi)存中,此時發(fā)生宕機就會導(dǎo)致緩存中的數(shù)據(jù)消失,數(shù)據(jù)庫中的數(shù)據(jù)就與宕機前redis中的數(shù)據(jù)不一致

綜上所述,雖然CacheAsidePattern方案是最復(fù)雜的一個,但是他也同樣是最可靠的一個,于是我們選擇它來進(jìn)行接下來的代碼學(xué)習(xí)

主動更新策略注意項

數(shù)據(jù)庫發(fā)生更新的時候直接刪除緩存中的該數(shù)據(jù),而不是跟著更新緩存,因為如果發(fā)生連續(xù)修改多次的情況,更新緩存的話更新次數(shù)等于數(shù)據(jù)庫的更新次數(shù);如果是刪除緩存數(shù)據(jù)的話就只需要刪除一次,下一次查詢直接從數(shù)據(jù)庫中查詢再寫入緩存。

刪除緩存數(shù)據(jù)和數(shù)據(jù)庫操作應(yīng)該保證原子性,也就是說刪除緩存數(shù)據(jù)操作和數(shù)據(jù)庫操作應(yīng)該同時成功或者同時失敗,那么該如何實現(xiàn)呢?單體式系統(tǒng)中,可以通過將兩個操作放在一個事務(wù)中來完成;分布式系統(tǒng)中可以利用TCC等分布式事務(wù)方案來實現(xiàn)

刪除緩存數(shù)據(jù)操作和數(shù)據(jù)庫操作的先后順序是什么?應(yīng)該是先寫數(shù)據(jù)庫再刪除緩存,原因是這種方式發(fā)生線程安全性問題的可能較小

主動更新的代碼實現(xiàn)

controller層前端交互

/**

*更新商鋪信息

*@paramshop商鋪數(shù)據(jù)

*@return無

@PutMapping

publicResultupdateShop(@RequestBodyShopshop){

//寫入數(shù)據(jù)庫

returnshopService.update(shop);

需要server的update方法,創(chuàng)建接口和實現(xiàn)類完成業(yè)務(wù)邏輯代碼編寫。主動更新+超時剔除的策略就只有兩步,那就是在寫緩存的時候設(shè)置超時時間,更新數(shù)據(jù)庫之后刪除緩存

//數(shù)據(jù)庫中存在寫入redis的時候設(shè)置超時時間

stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY+id,JSONUtil.toJsonStr(shop),RedisConstants.CACHE_SHOP_TTL,TimeUnit.MINUTES);

*更新商鋪信息

*@paramshop商鋪信息

*@return前端返回數(shù)據(jù)

@Override

@Transactional

publicResultupdate(Shopshop){

if

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論