Redis數(shù)據(jù)庫(kù)基礎(chǔ)與ASP.NET?Core緩存實(shí)現(xiàn)
基礎(chǔ)
Redis 庫(kù)
C# 下 Redis-Client 開(kāi)源的庫(kù)很多,有 BeetleX.Redis、csredis、Nhiredis、redis-sharp、redisboost、Rediska、ServiceStack.Redis、Sider、StackExchange.Redis、TeamDev Redis Client。
這里我們使用 StackExchange.Redis,另外 csredis 現(xiàn)在葉老板(Freesql作者)貢獻(xiàn)了大量維護(hù),并且葉老板新開(kāi)了一個(gè)叫 FreeRedis 的框架,目前正在開(kāi)發(fā)中,有興趣可以參與開(kāi)發(fā)或提出建議。
連接 Redis
創(chuàng)建一個(gè) .NET Core 項(xiàng)目,Nuget 庫(kù)添加引用 StackExchange.Redis ,使用最新版本。
Redis 默認(rèn)端口為 6379,如果要連接本地 Redis 服務(wù):
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost"); ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost:6379"); // ”{ip}:{port}“
如果使用 redis 集群,則使用 ,
分隔地址:
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("server1:port1,server2:port2,server3:port3");
可能要注意區(qū)分集群模式,多 redis 實(shí)例的地址,適合主從模式的集群或者 redis culster 集群,哨兵模式筆者還沒(méi)有測(cè)試過(guò)。
能用 redis 干啥
redis 具有很多應(yīng)用場(chǎng)景,一般使用到的場(chǎng)景有:
- 存儲(chǔ)數(shù)據(jù)(當(dāng)數(shù)據(jù)庫(kù)使用)
- 利用 pub/sub 做消息隊(duì)列
接下來(lái)將介紹這兩種場(chǎng)景的使用方法。
Redis 數(shù)據(jù)庫(kù)存儲(chǔ)
訪問(wèn) redis 數(shù)據(jù)庫(kù):
IDatabase db = redis.GetDatabase();
Redis 默認(rèn)有 16 個(gè)數(shù)據(jù)庫(kù),可以 GetDatabase(int db )
獲取指定的數(shù)據(jù)庫(kù)。
使用了 redis cluster 集群的 redis 節(jié)點(diǎn),只有一個(gè)數(shù)據(jù)庫(kù),不能自由選擇。這里我們只需要使用 redis.GetDatabase()
即可 。
Redis 使用比較簡(jiǎn)單的,大多時(shí)候,只要有相應(yīng)的應(yīng)用場(chǎng)景,我們查詢文檔很快就可以掌握,所以這里只介紹字符串的使用。
字符串
redis 的字符串參考:字符串string
IDatabase 中包含 string 類型的數(shù)據(jù)操作,其 API 使用 String
開(kāi)頭,辨識(shí)度高。
設(shè)置一個(gè)字符串?dāng)?shù)據(jù):
db.StringSet("A", "這是一條字符串?dāng)?shù)據(jù)的值"); var value = db.StringGet("A");
如果字符串使用 byte[] (二進(jìn)制)存儲(chǔ),也可以設(shè)置值:
byte[] str=... ... db.StringSet("A", str;
Redis 里面,還有其它很多類型,這里我們只介紹字符串,因?yàn)?API 其實(shí)就那么些,用到的時(shí)候再學(xué)也可以的。先學(xué)字符串的使用,其它就是觸類旁通了。
訂閱發(fā)布
訂閱某個(gè) Topic,當(dāng)其改變狀態(tài)時(shí),訂閱者可以收到通知,做分布式消息隊(duì)列也行。類似 MQTT 協(xié)議這樣。
獲取訂閱器:
ISubscriber sub = redis.GetSubscriber();
選擇訂閱的 Topic,并設(shè)置回調(diào)函數(shù):
sub.Subscribe("Message", (channel, message) => { Console.WriteLine((string)message); });
當(dāng)某一方訂閱了 Message
,在另一個(gè)地方,有別的客戶端(也可以是自己)推送 Topic :
sub.Publish("Message","你有一條新的消息,請(qǐng)注意查收");
Topic 推送后,訂閱方可以收到推送的消息。
測(cè)試代碼
ISubscriber sub = redis.GetSubscriber(); sub.Subscribe("Message", (channel, message) => { Console.WriteLine((string)message); }); Thread.Sleep(1000); sub.Publish("Message","你有一條新的消息,請(qǐng)注意查收");
channel :Topic 的名稱,即上面的 Message。
message:推送的消息內(nèi)容。
RedisValue
使用 API 設(shè)置值的時(shí)候,都會(huì)有這個(gè)參數(shù)。因?yàn)?Redis 中的值只能是 “字符串”,因此 C# 中也要遵守這種規(guī)則,但是 C# 是強(qiáng)類型語(yǔ)言,而且有那么多值類型,只使用 string ,編寫(xiě)代碼時(shí)會(huì)有諸多不便。
因此,就創(chuàng)建了 RedisValue 這個(gè)類型,里面有大量的隱式轉(zhuǎn)換重載,所以我們可以使用 C# 的簡(jiǎn)單類型存儲(chǔ)數(shù)據(jù)以及獲取數(shù)據(jù),避免手工轉(zhuǎn)換。
當(dāng)然這個(gè)說(shuō)法不是很準(zhǔn)確,使用 RedisValue 主要考慮轉(zhuǎn)換方便。
入門的知識(shí)就介紹到這里,更多的 Redis 知識(shí)可以查看官方文檔。下面開(kāi)始介紹 AS.NET Core 使用分布式緩存。
ASP.NET Core 緩存與分布式緩存
ASP.NET Core 里面有很多定義的標(biāo)準(zhǔn)接口,例如日志、緩存等,這些接口為開(kāi)發(fā)者設(shè)置了統(tǒng)一的定義和功能,上層服務(wù)不需要變更代碼就能切換類庫(kù),底層使用哪種庫(kù)對(duì)上層沒(méi)有影響。
ASP.NET Core 中的緩存,可以使用多種方式完成,例如 Redis,內(nèi)存,關(guān)系型數(shù)據(jù)庫(kù),文件緩存等。而且根據(jù)拓展性,可以分為本機(jī)緩存,分布式緩存。
本機(jī)緩存常見(jiàn)的是內(nèi)存緩存,內(nèi)存緩存可以存儲(chǔ)任何對(duì)象。 分布式緩存最常見(jiàn)的是 Redis,分布式緩存接口僅限 byte[]
(指參數(shù),繼續(xù)看到后面的小節(jié)就明白了) 。 內(nèi)存緩存和分布式緩存都使用鍵值對(duì)來(lái)存儲(chǔ)緩存項(xiàng)。
內(nèi)存中的緩存
ASP.NET Core 的內(nèi)存緩存
ASP.NET Core 內(nèi)存緩存是指一般是單機(jī)(本機(jī))使用的,一般這種內(nèi)存緩存框架是 System.Runtime
或 Microsoft 包提供的,因?yàn)椴恍枰紤]分布式或者復(fù)雜的結(jié)構(gòu),所以一般不需要第三方庫(kù)。這里的內(nèi)存緩存并不只是指數(shù)據(jù)在內(nèi)存中,所以需要區(qū)分 Redis 這類專業(yè)的緩存框架。且這里緩存只是作為提高性能而用。
這種緩存主要有兩種功能比較豐富的實(shí)現(xiàn) System.Runtime.Caching 和
MemoryCache。
在內(nèi)存中緩存、存儲(chǔ)數(shù)據(jù)
在 ASP.NET Core 的內(nèi)存緩存之外,我們來(lái)討論一下,編寫(xiě)代碼時(shí),自己設(shè)置的內(nèi)存緩存是否合理。
我們都知道,使用內(nèi)存緩存是為了提高代碼性能而用的。
這里筆者個(gè)人認(rèn)為可以從兩個(gè)層次來(lái)對(duì)這種緩存歸類討論。
第一種,對(duì)于要多次使用、而每次使用都需要計(jì)算、源數(shù)據(jù)相同則結(jié)果相同的,可以使用內(nèi)存緩存。例如反射就比較消耗時(shí)間(速度慢),可以使用內(nèi)存緩存起來(lái),下次直接取得信息而不需要重新計(jì)算。
下面筆者說(shuō)一下理由。
內(nèi)存緩存用在反射緩存這類緩存上,緩存的數(shù)據(jù)源是可確定的、可計(jì)算總量的,而且這部分內(nèi)存不需要頻繁增加或者減少,不僅提高了性能,對(duì) GC 來(lái)說(shuō)也可以一定程度上減少回收壓力,更重要的是開(kāi)發(fā)者可以降低緩存的復(fù)雜程度。
這種緩存主要為了避免重復(fù)計(jì)算,或者重復(fù)導(dǎo)入(例如加載程序集、從文件加載數(shù)據(jù))等。如果數(shù)據(jù)最近出現(xiàn)過(guò),而且后面一段時(shí)間不會(huì)變化,使用內(nèi)存來(lái)緩存也很實(shí)在,例如 MVC 的視圖、每15分鐘刷新一次的排行榜等。
第二種是使用內(nèi)存存儲(chǔ)數(shù)據(jù),很多人單純是因?yàn)閮?nèi)存存儲(chǔ)數(shù)據(jù)特別快,把內(nèi)存當(dāng)作數(shù)據(jù)庫(kù)來(lái)玩,因此很容易導(dǎo)致內(nèi)存泄露。最常見(jiàn)的就是使用靜態(tài)字典、靜態(tài)列表等,然后編寫(xiě)方法增刪查改數(shù)據(jù),這一類在壓力測(cè)試下或者請(qǐng)求量大一些、變動(dòng)比較頻繁的時(shí)候,內(nèi)存堆積特別厲害。
需要頻繁變化或需要實(shí)時(shí)變化的數(shù)據(jù),存儲(chǔ)在內(nèi)存中確實(shí)速度非???,如何確定數(shù)據(jù)失效、去除無(wú)用數(shù)據(jù)等需要有很深的考慮。
另外,在內(nèi)存中如使用字典大量存儲(chǔ)數(shù)據(jù),數(shù)據(jù)量很多的情況下,每次索引數(shù)據(jù)的時(shí)間都會(huì)變長(zhǎng),如果使用了 Linq 或者 for 或者 foreach 等檢索數(shù)據(jù),也很容易出現(xiàn)耗時(shí)長(zhǎng)的時(shí)間復(fù)雜度。這種情況下,你是相信自己的代碼,還是相信 Mysql、SqlServer 等數(shù)據(jù)庫(kù)? Hash 算法和紅黑樹(shù)都了解了嘛?
如果實(shí)在有需求需要使用內(nèi)存緩存數(shù)據(jù),并且可能動(dòng)態(tài)增加或移除數(shù)據(jù)的話,可以使用 WeakReference 弱引用,即在引用對(duì)象的同時(shí)仍然允許 GC 回收該對(duì)象。缺點(diǎn)是數(shù)據(jù)可能丟失,不適合需要持久化的數(shù)據(jù)。
但無(wú)論情況,我們可以確定:
- 緩存都是副本
- 緩存丟失不影響程序的使用
- 緩存不能無(wú)限增長(zhǎng)
- 緩存避免復(fù)雜結(jié)構(gòu)
- ... ...
IMemoryCache
IMemoryCache
提供的接口太少了:
ICacheEntry CreateEntry(object key); void Remove(object key); bool TryGetValue(object key, out object value);
適合單一的鍵值緩存。
此接口在 Microsoft.Extensions.Caching.Memory
中有實(shí)現(xiàn),例如 MemoryCache 。適合 ASP.NET Core 中使用。
MemoryCache
這里的 MemoryCache 并不是指 IMemoryCache 的實(shí)現(xiàn),而是指 System.Runtime.Caching.MemoryCache
,需要安裝 Nuget 包。
可以實(shí)現(xiàn)對(duì)實(shí)例對(duì)象的緩存,請(qǐng)查看查看官方文檔:https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.caching.memorycache?view=dotnet-plat-ext-3.1
另外內(nèi)存緩存還有一個(gè)分布式內(nèi)存緩存,但不是真正的分布式,信息可以參考:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/distributed?view=aspnetcore-3.1#distributed-memory-cache
分布式緩存
ASP.NET Core 分布式緩存,則使用了 IDistributedCache 這個(gè)統(tǒng)一的接口。如果你在 Nuget 搜索 IDistributedCache ,會(huì)發(fā)現(xiàn)相關(guān)的庫(kù)非常多。
分布式緩存的使用,除了最常見(jiàn)的 Redis,SQLServer 也行,只要實(shí)現(xiàn)了 IDistributedCache 就ok。
IDistributedCache
IDistributedCache 接口提供的方法實(shí)在太少了,有四個(gè)異步方法四個(gè)同步方法,這里只介紹異步方法。
方法 | 說(shuō)明 |
---|---|
GetAsync(String, CancellationToken) | 獲取一個(gè)鍵的值 |
RefreshAsync(String, CancellationToken) | 基于緩存中某個(gè)值的鍵刷新該值,并重置其可調(diào)到期超時(shí)(如果有) |
RemoveAsync(String, CancellationToken) | 刪除一個(gè)鍵 |
SetAsync(String, Byte[], DistributedCacheEntryOptions, CancellationToken) | 設(shè)置一個(gè)鍵的值 |
局限還是很大的,只能使用字符串。估計(jì)大家可能沒(méi)怎么使用?
ASP.NET Core 官方支持的分布式緩存,目前主要有 NCache、Redis、SqlServer。本節(jié)只討論 Redis。
Redis 緩存
StackExchange.Redis 是 ASP.NET Core 官方推薦的 Redis 框架,并且官方對(duì)其做了封裝,可以到 Nuget 搜索 Microsoft.Extensions.Caching.StackExchangeRedis
。
RedisCache 繼承了 IDistributedCache 接口。
Startup.ConfigureServices 中配置服務(wù)注冊(cè):
services.AddStackExchangeRedisCache(options => { options.Configuration = "ip:端口,ip1:端口,ip2:端口"; // redis 集群或單機(jī) options.InstanceName = "mvc"; // 實(shí)例 名稱 });
依賴注入:
private readonly IDistributedCache _cache;
示例:
public async Task<string> Test(string key,string value) { await _cache.SetStringAsync(key, value); return await _cache.GetStringAsync(key); }
設(shè)置緩存時(shí)間:
var options = new DistributedCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromSeconds(20)); await _cache.SetStringAsync(key, value, options);
到此這篇關(guān)于Redis數(shù)據(jù)庫(kù)基礎(chǔ)與ASP.NET Core緩存實(shí)現(xiàn)的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
ASP.NET?Core中MVC模式實(shí)現(xiàn)路由一
這篇文章介紹了ASP.NET?Core中MVC模式實(shí)現(xiàn)路由的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04.Net站點(diǎn)設(shè)置多個(gè)路由對(duì)應(yīng)同一個(gè)Action
這篇文章介紹了.Net站點(diǎn)設(shè)置多個(gè)路由對(duì)應(yīng)同一個(gè)Action的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07.Net MVC將Controller數(shù)據(jù)傳遞到View
這篇文章介紹了.Net MVC將Controller數(shù)據(jù)傳遞到View的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03ASP.NET MVC 4 中的JSON數(shù)據(jù)交互的方法
本篇文章主要介紹了ASP.NET MVC 4 中的JSON數(shù)據(jù)交互的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04一個(gè)簡(jiǎn)答的Access下的分頁(yè)asp.net代碼
一個(gè)簡(jiǎn)答的Access下的分頁(yè)asp.net代碼2010-03-03.NET Core Web APi大文件分片上傳研究實(shí)現(xiàn)
這篇文章主要介紹了.NET Core Web APi大文件分片上傳研究實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11asp.net中的check與uncheck關(guān)鍵字用法解析
這篇文章主要介紹了asp.net中的check與uncheck關(guān)鍵字用法,以實(shí)例形式較為詳細(xì)的分析了check與uncheck關(guān)鍵字的各種常見(jiàn)用法與使用時(shí)的注意事項(xiàng),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10