Redis 入门与 ASP.NET Core 缓存
如果你还没有 redis 集群,可以参考笔者的另一篇文章:搭建分布式 Redis Cluster 集群与 Redis 入门
本文将使用 StackExchange.Redis 库来连接和操作 Redis 。
StackExchange.Redis
的使用,本文只是参照文档,换种方式表示,如果英文基础好,建议阅读文档:https://stackexchange.github.io/StackExchange.Redis/Basics
本文内容介绍 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 的框架,目前正在开发中,有兴趣可以参与开发或提出建议。
连接 Redis
创建一个 .NET Core 项目,Nuget 库添加引用 StackExchange.Redis ,使用最新版本。
Redis 默认端口为 6379,如果要连接本地 Redis 服务:
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 集群,哨兵模式笔者还没有测试过。
能用 redis 干啥
redis 具有很多应用场景,一般使用到的场景有:
- 存储数据(当数据库使用)
- 利用 pub/sub 做消息队列
接下来将介绍这两种场景的使用方法。
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:推送的消息内容。
RedisValue
使用 API 设置值的时候,都会有这个参数。因为 Redis 中的值只能是 “字符串”,因此 C# 中也要遵守这种规则,但是 C# 是强类型语言,而且有那么多值类型,只使用 string ,编写代码时会有诸多不便。
因此,就创建了 RedisValue 这个类型,里面有大量的隐式转换重载,所以我们可以使用 C# 的简单类型存储数据以及获取数据,避免手工转换。
当然这个说法不是很准确,使用 RedisValue 主要考虑转换方便。
入门的知识就介绍到这里,更多的 Redis 知识可以查看官方文档。下面开始介绍 AS.NET Core 使用分布式缓存。
ASP.NET Core 缓存与分布式缓存
ASP.NET Core 里面有很多定义的标准接口,例如日志、缓存等,这些接口为开发者设置了统一的定义和功能,上层服务不需要变更代码就能切换类库,底层使用哪种库对上层没有影响。
ASP.NET Core 中的缓存,可以使用多种方式完成,例如 Redis,内存,关系型数据库,文件缓存等。而且根据拓展性,可以分为本机缓存,分布式缓存。
本机缓存常见的是内存缓存,内存缓存可以存储任何对象。 分布式缓存最常见的是 Redis,分布式缓存接口仅限 byte[]
(指参数,继续看到后面的小节就明白了) 。 内存缓存和分布式缓存都使用键值对来存储缓存项。
内存中的缓存
ASP.NET Core 的内存缓存
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
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
这里的 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
IDistributedCache 接口提供的方法实在太少了,有四个异步方法四个同步方法,这里只介绍异步方法。
方法 说明 GetAsync(String, CancellationToken) 获取一个键的值 RefreshAsync(String, CancellationToken) 基于缓存中某个值的键刷新该值,并重置其可调到期超时(如果有) RemoveAsync(String, CancellationToken) 删除一个键 SetAsync(String, Byte[], DistributedCacheEntryOptions, CancellationToken) 设置一个键的值
局限还是很大的,只能使用字符串。估计大家可能没怎么使用?
ASP.NET Core 官方支持的分布式缓存,目前主要有 NCache、Redis、SqlServer。本节只讨论 Redis。
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);
Redis 入门与 ASP.NET Core 缓存的更多相关文章
- Asp.net Core 缓存 MemoryCache 和 Redis
Asp.net Core 缓存 MemoryCache 和 Redis 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitH ...
- ASP.NET Core 缓存技术 及 Nginx 缓存配置
前言 在Asp.Net Core Nginx部署一文中,主要是讲述的如何利用Nginx来实现应用程序的部署,使用Nginx来部署主要有两大好处,第一是利用Nginx的负载均衡功能,第二是使用Nginx ...
- 【无私分享:ASP.NET CORE 项目实战(第十一章)】Asp.net Core 缓存 MemoryCache 和 Redis
目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitHub上下载了十几个源码参考, Memory 和 Redis 终于写出一个 ...
- asp.net core 缓存和Session
缓存 缓存在内存中 ASP.NET Core 使用 IMemoryCache内存中缓存是使用依赖关系注入从应用中引用的服务. 请在ConfigureServices中调用AddMemoryCache( ...
- C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式
C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...
- ASP.NET Core缓存静态资源
背景 缓存样式表,JavaScript或图像文件等静态资源可以提高您网站的性能.在客户端,总是从缓存中加载一个静态文件,这样可以减少对服务器的请求数量,从而减少获取页面及其资源的时间.在服务器端,由于 ...
- 菜鸟入门【ASP.NET Core】5:命令行配置、Json文件配置、Bind读取配置到C#实例、在Core Mvc中使用Options
命令行配置 我们通过vs2017创建一个控制台项目CommandLineSample 可以看到现在项目以来的是dotnet core framework 我们需要吧asp.net core引用进来 ...
- Asp.Net Core 缓存的使用(译)
原文:http://www.binaryintellect.net/articles/a7d9edfd-1f86-45f8-a668-64cc86d8e248.aspx环境:Visual Studio ...
- 菜鸟入门【ASP.NET Core】1:环境安装
下载.NET Core SDK 下载地址:https://www.microsoft.com/net/download/windows https://www.microsoft.com/net/le ...
随机推荐
- 12.扩展:向量空间模型算法(Vector Space Model)
- ftp自动上传下载同步工具 免费好用的ftp自动上传下载同步工具
有时我们需要定时上传文件到FTP,可大多数FTP工具并不支持定时上传功能,这时我们就需要可以定时ftp上传的工具(服务器管理工具).它是一款功能强大的服务器集成管理器,包含win系统和linux系统的 ...
- C#实现创建、编辑NX表达式
在NX8.5中使用C#编辑表达式中有个坑,part.Expressions.Edit该方法鲁棒性很差,当表达式有错时也能编辑成功(手动在NX中增加错误表达式会有弹框,无法创建,而该方法却可以,疑是bu ...
- 微服务实战系列(四)-注册中心springcloud alibaba nacos
1.场景描述 因要用到微服务,关于注册中心这块,与同事在技术原型上做了讨论,初步定的方案是使用:阿里巴巴的nacos+springcloud gateway,下面表格是同事整理的注册中心对比,以前用的 ...
- [BJDCTF2020]EzPHP
[BJDCTF2020]EzPHP 解码:http://794983a5-f5dc-4a13-bc0b-ca7140ba23f3.node3.buuoj.cn/1nD3x.php 源代码: <? ...
- Ubuntu16.04+Tensorflow+CUDA9.0+cuDNN7.0 环境简明搭建指南
最近在研究风格化得内容,发现搭建环境实在是很头疼的事情,虽然网上已经有各路大神总结整理好了很多搭建指南,各种问题的解决方案都已经罗列出来供大家参考.然后参考终究是参考,真正自己上手,发现仍旧是各种坑, ...
- JVM内存模型不再是秘密
前言 上篇文章我们一起了解了jvm虚拟机类的加载机制,而且是以一种纯大白话进行的一场闲聊,相信小伙伴们应该印象深刻,感兴趣的小伙伴可以重温一下上一篇文章大白话谈JVM的类加载机制. 当jvm加载了类后 ...
- gRPC-微服务间通信实践
微服务间通信常见的两种方式 由于微服务架构慢慢被更多人使用后,迎面而来的问题是如何做好微服务间通信的方案.我们先分析下目前最常用的两种服务间通信方案. gRPC(rpc远程调用) 场景:A服务主动发起 ...
- Java知识系统回顾整理01基础04操作符03逻辑运算符
一.长路与 和 短路与 无论长路与还是短路与 两边的运算单元都是布尔值 都为真时,才为真 任意为假,就为假 区别 长路与 两侧,都会被运算 短路与 只要第一个是false,第二个就不进行运算了 pub ...
- Example Code for a TMP102 I2c Thermometer————Arduino
参考:https://playground.arduino.cc/Code/TMP102/ Example Code for a TMP102 I2c Thermometer I've fairly ...