.NetCore之介面快取
1、問題:我們平時做開發的時候肯定都有用到快取這個功能,一般寫法是在需要的業務程式碼裡讀取快取、判斷是否存在、不存在則讀取資料庫再設定快取這樣一個步驟。 但是如果我們有很多地方業務都有用到快取,我們就需要在每個地方都寫關於快取的程式碼,這樣會造成很多重複程式碼,同時對業務侵入不利於後續的開發維護。
2、一般的解決辦法是將快取的功能提取出來,然後在需要用到快取的地方呼叫即可。這樣確實減少了很多重複程式碼,但這樣還是會存在整個專案通用的快取功能侵入業務程式碼,那我們有什麼辦法將快取功能完全提取出來,達到業務程式碼零侵入呢?
3、既然我們快取存的是介面的業務資料,那麼為何我們不能直接把整個介面快取起來呢,即將整個介面返回的資料快取?同時要達到業務零侵入,那我們是不是想到了反射、特性呢?沒錯,我們使用的就是ActionFilterAttribute,關於ActionFilterAttribute無非就是OnActionExecuting(執行動作方法前觸發)、OnActionExecuted(執行動作方法後觸發)、OnResultExecuting(在執行操作結果之前觸發)、OnResultExecuted(在執行操作結果之後觸發)這四個方法,相信很多小夥伴都用到過,這裡就不細說了。那我們現在的解決方案是:在OnActionExecuting(執行動作方法前觸發)裡判斷是否存在快取,如果存在則不去執行介面業務,直接返回資料。還有一個問題,一般介面都會有入參,入參不同輸出的資料也不同(比如我有一個分頁的介面,傳的page引數不同,得到的結果也不同),這個怎麼解決呢? 我們只需要把介面所有引數拼湊起來,然後MD5加密成一個字串,將其作為快取的key,那麼即使同一個介面、引數不同也會得到不同的key。
4、廢話不多說,直接上程式碼。
SignHeader = CacheMinutes = ApiCache( SignHeader = , CacheMinutes = .SignHeader =.CacheMinutes = cacheKey = data = (! content = == = , , = (filterContext.HttpContext.Response.Headers.ContainsKey()) cacheKey = data = JsonSerializer.Serialize((filterContext.Result disData = JsonSerializer.Deserialize<Dictionary<, >>(disData.ContainsKey() && disData[]=== keyContent = request.Host.Value + request.Path.Value + request.QueryString.Value + request.Method + request.ContentType + (request.Method.ToUpper() != && request.Method.ToUpper() != && request.Form.Count > ( item += $ hs = request.Headers.Where(a => !( [] { , }).Contains(a.Key)).ToDictionary(a => ( item += $
這裡使用的是redis,也可以選擇其他的,程式碼簡單沒有做適配,這樣我們只需要在用到快取的介面上加上 [ApiCache(CacheMinutes =1)]特性就行啦,關於引數的話也可以根據自己的業務需求來定製。
5、關於快取的三座大山: 快取穿透、快取擊穿、快取雪崩,這塊網上有很多的資料可以看,這裡只做一個簡單的介紹跟解決思路。
快取穿透:訪問一個不存在的key時,請求會穿過快取直接請求資料庫。比如現在有個介面是分頁的,然後客戶端請求介面的時候將pageindex引數給的很大,大到該介面不可能有這麼多頁的資料時,每次請求都會穿過快取去查資料庫。如果有人故意攻擊介面就會給資料庫造成巨大壓力甚至掛掉。當然,這裡我們肯定也要做一些業務引數的校驗,比如每頁條數不能超過多少之類的,總之不能輕信客戶端傳過來的引數。
解決方案:最簡單有效的解決方案是當在資料庫也查不到資料的時候,設定一個value為null的快取值(該值的過期時間要儘量短),這樣就可以避免惡意攻擊。另外就是使用布隆過濾器。
我們這裡使用的解決方案是第一種設定null值,在上述的程式碼中有註釋。不過這裡最好介面有一個返回規範,比如每個介面返回固定值:message、code、data這幾個欄位, 那麼我們只需判斷data是否為空來設定過期時間。
快取擊穿:某一個訪問量極高的key過期,導致所有請求打在資料庫上。
解決方案:將訪問量高德key設定永不過期、使用互斥鎖。我們這裡使用設定key永不過期就行,具體實現就是加一個是否過期的欄位從外部傳入,再根據該欄位判斷是否設定過期時間。同時可以寫一個定時任務去更新設定為永不過期的key值。
快取雪崩:某一時刻多個高訪問量的key同時過期。
解決方案:在設定過期時間的時候將每個key的過期時間設定分佈開來,在上述程式碼中CacheMinutes欄位改成過期時間範圍從。。。到。。。,然後key的過期時間從範圍中取一個隨機值。
當然這裡講到的解決方案也只是個人常用的,也可以使用其他解決方案。
6、最後,已經很久沒更新部落格了,是我太懶了,只想白p別人的文章。還是很敬佩哪些經常更新部落格的大佬,首先文章要有技術點、然後還要考慮怎樣將自己對技術點的想法、經驗、理解表達出來,真的很不容易。然後就是文章有什麼錯誤點或者可以改進的地方望指正。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69983372/viewspace-2721909/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- NetCore的快取使用詳例NetCore快取
- ETag 介面軟快取快取
- 快取工廠之Redis快取快取Redis
- .netcore 寫快遞100的快遞物流資訊查詢介面NetCore
- Java高併發快取架構,快取雪崩、快取穿透之謎Java快取架構穿透
- HTTP深入之快取HTTP快取
- C#之快取C#快取
- 兩級快取實現分析之快取設定快取
- Django高階之-快取Django快取
- 快取穿透、快取擊穿、快取雪崩、快取預熱快取穿透
- 快取策略之瀏覽器快取瀏覽器
- 面試精選之http快取面試HTTP快取
- 分散式之快取擊穿分散式快取
- 快取穿透、快取擊穿、快取雪崩快取穿透
- 快取穿透、快取雪崩、快取擊穿快取穿透
- Redis快取擊穿、快取穿透、快取雪崩Redis快取穿透
- HTTP快取——協商快取(快取驗證)HTTP快取
- [Redis]快取穿透/快取擊穿/快取雪崩Redis快取穿透
- 快取穿透 快取雪崩快取穿透
- 跟我一起學.NetCore之WebApi介面裸奔有風險(Jwt)NetCoreWebAPIJWT
- 快取問題(一) 快取穿透、快取雪崩、快取併發 核心概念快取穿透
- lodash原始碼分析之List快取原始碼快取
- LSM-Tree - LevelDb之LRU快取快取
- rfc7234之http快取HTTP快取
- PWA之Workbox快取策略分析快取
- 分散式快取系統之Memcached分散式快取
- lodash原始碼分析之Hash快取原始碼快取
- 微信小程式之資料快取微信小程式快取
- .NET之頁面資料快取快取
- 快取穿透、快取擊穿、快取雪崩區別快取穿透
- 快取問題(四) 快取穿透、快取雪崩、快取併發 解決案例快取穿透
- ServiceWorker 快取與 HTTP 快取快取HTTP
- mybatis快取-二級快取MyBatis快取
- MyBatis快取機制(一級快取,二級快取)MyBatis快取
- 快取、快取演算法和快取框架簡介快取演算法框架
- 快取淘汰、快取穿透、快取擊穿、快取雪崩、資料庫快取雙寫一致性快取穿透資料庫
- 在 WPF 客戶端實現 AOP 和介面快取客戶端快取
- 新增發快遞上門取件的介面-快遞鳥預約上門取件API對接API