ASP.Net Core 使用Redis實現分布式緩存


本篇我們記錄的內容是怎么在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;

}

 

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;

}

 

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);

}

 

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;

}

 

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;

}

 

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;

}

 

三、文章內容調用

 

以上是代碼的封裝:下面是在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();

}

 

5、我是用CoreAPI來寫的 控制器中代碼如下:

 

1)先實例對象

 

private DistributedCache _Cache;

 

/// <summary>

///   構造注入

/// </summary>

/// <param name="Cache"></param>

public ValuesController(IDistributedCache Cache)

{

    _Cache = new DistributedCache(Cache);

}

 

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();

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM