若是你尚未 redis 集羣,能夠參考筆者的另外一篇文章:搭建分佈式 Redis Cluster 集羣與 Redis 入門html
本文將使用 StackExchange.Redis 庫來鏈接和操做 Redis 。git
StackExchange.Redis
的使用,本文只是參照文檔,換種方式表示,若是英文基礎好,建議閱讀文檔:https://stackexchange.github.io/StackExchange.Redis/Basicsgithub
本文內容介紹 StackExchange.Redis
的使用基礎,而後介紹 ASP.NET Core 中的緩存、如何使用 Redis。redis
C# 下 Redis-Client 開源的庫不少,有 BeetleX.Redis、csredis、Nhiredis、redis-sharp、redisboost、Rediska、ServiceStack.Redis、Sider、StackExchange.Redis、TeamDev Redis Client。算法
這裏咱們使用 StackExchange.Redis,另外 csredis 如今葉老闆(Freesql做者)貢獻了大量維護,而且葉老闆新開了一個叫 FreeRedis 的框架,目前正在開發中,有興趣能夠參與開發或提出建議。sql
建立一個 .NET Core 項目,Nuget 庫添加引用 StackExchange.Redis ,使用最新版本。數據庫
Redis 默認端口爲 6379,若是要鏈接本地 Redis 服務:api
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost"); ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost:6379"); // 」{ip}:{port}「
若是使用 redis 集羣,則使用 ,
分隔地址:緩存
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("server1:port1,server2:port2,server3:port3");
可能要注意區分集羣模式,多 redis 實例的地址,適合主從模式的集羣或者 redis culster 集羣,哨兵模式筆者尚未測試過。mvc
redis 具備不少應用場景,通常使用到的場景有:
接下來將介紹這兩種場景的使用方法。
訪問 redis 數據庫:
IDatabase db = redis.GetDatabase();
Redis 默認有 16 個數據庫,能夠 GetDatabase(int db )
獲取指定的數據庫。
使用了 redis cluster 集羣的 redis 節點,只有一個數據庫,不能自由選擇。這裏咱們只須要使用 redis.GetDatabase()
便可 。
Redis 使用比較簡單的,大多時候,只要有相應的應用場景,咱們查詢文檔很快就能夠掌握,因此這裏只介紹字符串的使用。
redis 的字符串參考:https://www.cnblogs.com/whuanle/p/13837153.html#字符串string
IDatabase 中包含 string 類型的數據操做,其 API 使用 String
開頭,辨識度高。
設置一個字符串數據:
db.StringSet("A", "這是一條字符串數據的值"); var value = db.StringGet("A");
若是字符串使用 byte[] (二進制)存儲,也能夠設置值:
byte[] str=... ... db.StringSet("A", str;
Redis 裏面,還有其它不少類型,這裏咱們只介紹字符串,由於 API 其實就那麼些,用到的時候再學也能夠的。先學字符串的使用,其它就是舉一反三了。
訂閱某個 Topic,當其改變狀態時,訂閱者能夠收到通知,作分佈式消息隊列也行。相似 MQTT 協議這樣。
獲取訂閱器:
ISubscriber sub = redis.GetSubscriber();
選擇訂閱的 Topic,並設置回調函數:
sub.Subscribe("Message", (channel, message) => { Console.WriteLine((string)message); });
當某一方訂閱了 Message
,在另外一個地方,有別的客戶端(也能夠是本身)推送 Topic :
sub.Publish("Message","你有一條新的消息,請注意查收");
Topic 推送後,訂閱方能夠收到推送的消息。
測試代碼
ISubscriber sub = redis.GetSubscriber(); sub.Subscribe("Message", (channel, message) => { Console.WriteLine((string)message); }); Thread.Sleep(1000); sub.Publish("Message","你有一條新的消息,請注意查收");
channel :Topic 的名稱,即上面的 Message。
message:推送的消息內容。
使用 API 設置值的時候,都會有這個參數。由於 Redis 中的值只能是 「字符串」,所以 C# 中也要遵照這種規則,可是 C# 是強類型語言,並且有那麼多值類型,只使用 string ,編寫代碼時會有諸多不便。
所以,就建立了 RedisValue 這個類型,裏面有大量的隱式轉換重載,因此咱們可使用 C# 的簡單類型存儲數據以及獲取數據,避免手工轉換。
固然這個說法不是很準確,使用 RedisValue 主要考慮轉換方便。
入門的知識就介紹到這裏,更多的 Redis 知識能夠查看官方文檔。下面開始介紹 AS.NET Core 使用分佈式緩存。
ASP.NET Core 裏面有不少定義的標準接口,例如日誌、緩存等,這些接口爲開發者設置了統一的定義和功能,上層服務不須要變動代碼就能切換類庫,底層使用哪一種庫對上層沒有影響。
ASP.NET Core 中的緩存,可使用多種方式完成,例如 Redis,內存,關係型數據庫,文件緩存等。並且根據拓展性,能夠分爲本機緩存,分佈式緩存。
本機緩存常見的是內存緩存,內存緩存能夠存儲任何對象。 分佈式緩存最多見的是 Redis,分佈式緩存接口僅限 byte[]
(指參數,繼續看到後面的小節就明白了) 。 內存緩存和分佈式緩存都使用鍵值對來存儲緩存項。
ASP.NET Core 內存緩存是指通常是單機(本機)使用的,通常這種內存緩存框架是 System.Runtime
或 Microsoft 包提供的,由於不須要考慮分佈式或者複雜的結構,因此通常不須要第三方庫。這裏的內存緩存並不僅是指數據在內存中,因此須要區分 Redis 這類專業的緩存框架。且這裏緩存只是做爲提升性能而用。
這種緩存主要有兩種功能比較豐富的實現 System.Runtime.Caching 和
MemoryCache`。
在 ASP.NET Core 的內存緩存以外,咱們來討論一下,編寫代碼時,本身設置的內存緩存是否合理。
咱們都知道,使用內存緩存是爲了提升代碼性能而用的。
這裏筆者我的認爲能夠從兩個層次來對這種緩存歸類討論。
第一種,對於要屢次使用、而每次使用都須要計算、源數據相同則結果相同的,可使用內存緩存。例如反射就比較消耗時間(速度慢),可使用內存緩存起來,下次直接取得信息而不須要從新計算。
下面筆者說一下理由。
內存緩存用在反射緩存這類緩存上,緩存的數據源是可肯定的、可計算總量的,並且這部份內存不須要頻繁增長或者減小,不只提升了性能,對 GC 來講也能夠必定程度上減小回收壓力,更重要的是開發者能夠下降緩存的複雜程度。
這種緩存主要爲了不重複計算,或者重複導入(例如加載程序集、從文件加載數據)等。若是數據最近出現過,並且後面一段時間不會變化,使用內存來緩存也很實在,例如 MVC 的視圖、每15分鐘刷新一次的排行榜等。
第二種是使用內存存儲數據,不少人單純是由於內存存儲數據特別快,把內存看成數據庫來玩,所以很容易致使內存泄露。最多見的就是使用靜態字典、靜態列表等,而後編寫方法增刪查改數據,這一類在壓力測試下或者請求量大一些、變更比較頻繁的時候,內存堆積特別厲害。
須要頻繁變化或須要實時變化的數據,存儲在內存中確實速度很是快,如何肯定數據失效、去除無用數據等須要有很深的考慮。
另外,在內存中如使用字典大量存儲數據,數據量不少的狀況下,每次索引數據的時間都會變長,若是使用了 Linq 或者 for 或者 foreach 等檢索數據,也很容易出現耗時長的時間複雜度。這種狀況下,你是相信本身的代碼,仍是相信 Mysql、SqlServer 等數據庫? Hash 算法和紅黑樹都瞭解了嘛?
若是實在有需求須要使用內存緩存數據,而且可能動態增長或移除數據的話,可使用 WeakReference 弱引用,即在引用對象的同時仍然容許 GC 回收該對象。缺點是數據可能丟失,不適合須要持久化的數據。
但不管狀況,咱們能夠肯定:
IMemoryCache
提供的接口太少了:
ICacheEntry CreateEntry(object key); void Remove(object key); bool TryGetValue(object key, out object value);
適合單一的鍵值緩存。
此接口在 Microsoft.Extensions.Caching.Memory
中有實現,例如 MemoryCache 。適合 ASP.NET Core 中使用。
這裏的 MemoryCache 並非指 IMemoryCache 的實現,而是指 System.Runtime.Caching.MemoryCache
,須要安裝 Nuget 包。
能夠實現對實例對象的緩存,請查看查看官方文檔:https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.caching.memorycache?view=dotnet-plat-ext-3.1
另外內存緩存還有一個分佈式內存緩存,但不是真正的分佈式,信息能夠參考:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/distributed?view=aspnetcore-3.1#distributed-memory-cache
ASP.NET Core 分佈式緩存,則使用了 IDistributedCache 這個統一的接口。若是你在 Nuget 搜索 IDistributedCache ,會發現相關的庫很是多。
分佈式緩存的使用,除了最多見的 Redis,SQLServer 也行,只要實現了 IDistributedCache 就ok。
IDistributedCache 接口提供的方法實在太少了,有四個異步方法四個同步方法,這裏只介紹異步方法。
方法 | 說明 |
---|---|
GetAsync(String, CancellationToken) | 獲取一個鍵的值 |
RefreshAsync(String, CancellationToken) | 基於緩存中某個值的鍵刷新該值,並重置其可調到期超時(若是有) |
RemoveAsync(String, CancellationToken) | 刪除一個鍵 |
SetAsync(String, Byte[], DistributedCacheEntryOptions, CancellationToken) | 設置一個鍵的值 |
侷限仍是很大的,只能使用字符串。估計你們可能沒怎麼使用?
ASP.NET Core 官方支持的分佈式緩存,目前主要有 NCache、Redis、SqlServer。本節只討論 Redis。
StackExchange.Redis 是 ASP.NET Core 官方推薦的 Redis 框架,而且官方對其作了封裝,能夠到 Nuget 搜索 Microsoft.Extensions.Caching.StackExchangeRedis
。
RedisCache 繼承了 IDistributedCache 接口。
Startup.ConfigureServices 中配置服務註冊:
services.AddStackExchangeRedisCache(options => { options.Configuration = "ip:端口,ip1:端口,ip2:端口"; // redis 集羣或單機 options.InstanceName = "mvc"; // 實例 名稱 });
依賴注入:
private readonly IDistributedCache _cache;
示例:
public async Task<string> Test(string key,string value) { await _cache.SetStringAsync(key, value); return await _cache.GetStringAsync(key); }
設置緩存時間:
var options = new DistributedCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromSeconds(20)); await _cache.SetStringAsync(key, value, options);