原文地址:https://www.cnblogs.com/szlblog/p/9045209.html AspNetCore 使用Redis實現分散式緩存 上一篇講到了,Core的內置緩存:IMemoryCache,以及緩存的基礎概念。本篇會進行一些概念上的補充。 本篇我們記錄的內容是怎麼在Core ...
原文地址:https://www.cnblogs.com/szlblog/p/9045209.html
AspNetCore 使用Redis實現分散式緩存
上一篇講到了,Core的內置緩存:IMemoryCache,以及緩存的基礎概念。本篇會進行一些概念上的補充。
本篇我們記錄的內容是怎麼在Core中使用Redis 和 SQL Server 實現分散式緩存。
一、文章概念描述
分散式緩存描述:
分散式緩存重點是在分散式上,相信大家接觸過的分散式有很多中,像分散式開發,分散式部署,分散式鎖、事物、系統 等有很多。使我們對分散式本身就有一個很明確的認識,分散式就是有多個應用程式組成,可能分佈在不同的伺服器上,最終都是在為web端提供服務。
分散式緩存有以下幾點優點:
(1)所有的Web伺服器上的緩存數據都是相同的,不會因為應用程式不同,伺服器的不同導致緩存數據的不一樣。
(2)緩存的是獨立的不受Web伺服器的重新啟動或被刪除添加的影響,也就是說這些Web的改變不到導致緩存數據的改變。
傳統的單體應用架構因為用戶的訪問量的不高,緩存的存在大多數都是存儲用戶的信息,以及一些頁面,大多數的操作都是直接和DB進行讀寫交互,這種架構簡單,也稱為簡單架構,
傳統的OA項目比如ERP,SCM,CRM等系統因為用戶量不大也是因為大多數公司業務的原因,單體應用架構還是很常用的架構,但是有些系統隨著用戶量的增加,業務的擴張擴展,導致DB的瓶頸的出現。
以下我所瞭解到的關於這種情況的處理有以下兩種
(1):當用戶訪問量不大,但是讀寫的數據量很大的時候,我們一般採取的是,對DB進行讀寫分離、一主多從、對硬體進行升級的方式來解決DB瓶頸的問題。
這樣的缺點也同樣純在:
1、用戶量大的時候怎麼辦?,
2、對於性能的提升有限,
3、性價比不高。提升一點性能就需要花費很多代價,(打個比方,現在的I/O吞吐量是0.9的需要提升到1.0,我們在增加機器配置的情況下這個價格確實很可觀的)
(2):當用戶訪問量也增加的時候,我們就需要引入緩存了來解決了,一張圖描述緩存的大致的作用。
緩存主要針對的是不經常發生改變的並且訪問量很大的數據,DB資料庫可以理解為只作為數據固化的或者只用來讀取經常發生改變的數據,上圖中我沒有畫SET的操作,就是想特意說明一下,緩存的存在可以作為一個臨時的資料庫,我們可以通過定時的任務的方式去同步緩存和資料庫中的數據,這樣做的好處是可以轉移資料庫的壓力到緩存中。
緩存的出現解決了資料庫壓力的問題,但是當以下情況發生的時候,緩存就不在起到作用了,緩存穿透、緩存擊穿、緩存雪崩這三種情況。
緩存穿透:我們的程式中用緩存的時候一般採取的是先去緩存中查詢我們想要的緩存數據,如果緩存中不存在我們想要的數據的話,緩存就失去了做用(緩存失效)我們就是需要伸手向DB庫去要數據,這個時候這種動作過多資料庫就崩潰了,這種情況需要我們去預防了。比如說:我們向緩存獲取一個用戶信息,但是故意去輸入一個緩存中不存在的用戶信息,這樣就避過了緩存,把壓力重新轉移到數據上面了。對於這種問題我們可以採取,把第一次訪問的數據進行緩存,因為緩存查不到用戶信息,資料庫也查詢不到用戶信息,這個時候避免重覆的訪問我們把這個請求緩存起來,把壓力重新轉向緩存中,有人會有疑問了,當訪問的參數有上萬個都是不重覆的參數並且都是可以躲避緩存的怎麼辦,我們同樣把數據存起來設置一個較短過期時間清理緩存。
緩存擊穿:事情是這樣的,對於一些設置了過期時間的緩存KEY,在過期的時候,程式被高併發的訪問了(緩存失效),這個時候使用互斥鎖來解決問題,
互斥鎖原理:通俗的描述就是,一萬個用戶訪問了,但是只有一個用戶可以拿到訪問資料庫的許可權,當這個用戶拿到這個許可權之後重新創建緩存,這個時候剩下的訪問者因為沒有拿到許可權,就原地等待著去訪問緩存。
永不過期:有人就會想了,我不設置過期時間不就行了嗎?可以,但是這樣做也是有缺點的,我們需要定期的取更新緩存,這個時候緩存中的數據比較延遲。
緩存雪崩:是指多種緩存設置了同一時間過期,這個時候大批量的數據訪問來了,(緩存失效)資料庫DB的壓力又上來了。解決方法在設置過期時間的時候在過期時間的基礎上增加一個隨機數儘可能的保證緩存不會大面積的同事失效。
二、文章內容實現
在AspNetCore中使用 Redis實現緩存:
在項目中引用:using Microsoft.Extensions.Caching.Distributed; 使用IDistributedCache
IDistributedCache 介面
IDistributedCache介面包含同步和非同步方法。 介面允許在分散式緩存實現中添加、檢索和刪除項。 IDistributedCache介面包含以下方法:
Get、 GetAsync
採用字元串鍵並以byte[]形式檢索緩存項(如果在緩存中找到)。
Set、SetAsync
使用字元串鍵向緩存添加項byte[]形式)。
Refresh、RefreshAsync
根據鍵刷新緩存中的項,並重置其可調過期超時值(如果有)。
Remove、RemoveAsync
根據鍵刪除緩存項。
以下是我的代碼封裝DistributedCache類名:主要針對IDistributedCache中非非同步方法,非同步只寫了一個簡單的例子:
1、Get()獲取緩存
/// <summary> /// 獲取緩存 /// </summary> /// <param name="key"></param> /// <returns></returns> public object Get(string key) { string ReturnStr = ""; if (!string.IsNullOrEmpty(key)) { if (Exists(key)) { ReturnStr = Encoding.UTF8.GetString(_cache.Get(key)); } } return ReturnStr; }View Code
2、GetAsync()非同步獲取緩存
/// <summary> /// 使用非同步獲取緩存信息 /// </summary> /// <param name="key"></param> /// <returns></returns> public async Task<object> GetAsync(string key) { string ReturnString = null; var value = await _cache.GetAsync(key); if (value != null) { ReturnString = Encoding.UTF8.GetString(value); } return ReturnString; }View Code
3、Set()設置或添加緩存
/// <summary> /// 添加緩存 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public bool Add(string key, object value) { byte[] val = null; if (value.ToString() != "") { val = Encoding.UTF8.GetBytes(value.ToString()); } DistributedCacheEntryOptions options = new DistributedCacheEntryOptions(); //設置絕對過期時間 兩種寫法 options.AbsoluteExpiration = DateTime.Now.AddMinutes(30); // options.SetAbsoluteExpiration(DateTime.Now.AddMinutes(30)); //設置滑動過期時間 兩種寫法 options.SlidingExpiration = TimeSpan.FromSeconds(30); //options.SetSlidingExpiration(TimeSpan.FromSeconds(30)); //添加緩存 _cache.Set(key, val, options); //刷新緩存 _cache.Refresh(key); return Exists(key); }View Code
4、Remove()刪除緩存
/// <summary> /// 刪除緩存 /// </summary> /// <param name="key"></param> /// <returns></returns> public bool Remove(string key) { bool ReturnBool = false; if (key != "" || key != null) { _cache.Remove(key); if (Exists(key) == false) { ReturnBool = true; } } return ReturnBool; }View Code
5、修改緩存
/// <summary> /// 修改緩存 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public bool Modify(string key, object value) { bool ReturnBool = false; if (key != "" || key != null) { if (Remove(key)) { ReturnBool = Add(key, value.ToString()); } } return ReturnBool; }View Code
6、驗證緩存是否存在
/// <summary> /// 驗證是否存在 /// </summary> /// <param name="key"></param> /// <returns></returns> public bool Exists(string key) { bool ReturnBool = true; byte[] val = _cache.Get(key); if (val == null || val.Length == 0) { ReturnBool = false; } return ReturnBool; }View Code
三、文章內容調用
以上是代碼的封裝:下麵是在AspnetCore中調用
1、首先安裝Redis緩存:這個網上找個下載安裝就行
2、然後下載安裝:客戶端工具:RedisDesktopManager(方便管理)
3、在我們的項目Nuget中 引用 Microsoft.Extensions.Caching.Redis
4、在項目啟動Setup.cs中註冊:Redis服務:代碼如下
public void ConfigureServices(IServiceCollection services) { //將Redis分散式緩存服務添加到服務中 services.AddDistributedRedisCache(options => { //用於連接Redis的配置 Configuration.GetConnectionString("RedisConnectionString")讀取配置信息的串 options.Configuration = "localhost";// Configuration.GetConnectionString("RedisConnectionString"); //Redis實例名RedisDistributedCache options.InstanceName = "RedisDistributedCache"; }); services.AddMvc(); }View Code
5、我是用CoreAPI來寫的 控制器中代碼如下:
1)先實例對象
private DistributedCache _Cache; /// <summary> /// 構造註入 /// </summary> /// <param name="Cache"></param> public ValuesController(IDistributedCache Cache) { _Cache = new DistributedCache(Cache); }View Code
2)調用DistributedCache 類中的方法 代碼如下:
[HttpGet("{id}")] public string Get(int id) { //添加 bool booladd = _Cache.Add("id", "sssss"); //驗證 bool boolExists = _Cache.Exists("id"); //獲取 object obj = _Cache.Get("id"); //刪除 bool boolRemove = _Cache.Remove("id"); //修改 bool boolModify = _Cache.Modify("id", "ssssssss"); return obj.ToString(); }View Code