Redis入门与ASP.NET Core缓存

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis入门与ASP.NET Core缓存

基础


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 主要考虑转换方便。


微信图片_20220504120501.png

入门的知识就介绍到这里,更多的 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.CachingMemoryCache`。


在内存中缓存、存储数据

在 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。

微信图片_20220504120506.png


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实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
26天前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
2月前
|
缓存 NoSQL Java
Redis深度解析:解锁高性能缓存的终极武器,让你的应用飞起来
【8月更文挑战第29天】本文从基本概念入手,通过实战示例、原理解析和高级使用技巧,全面讲解Redis这一高性能键值对数据库。Redis基于内存存储,支持多种数据结构,如字符串、列表和哈希表等,常用于数据库、缓存及消息队列。文中详细介绍了如何在Spring Boot项目中集成Redis,并展示了其工作原理、缓存实现方法及高级特性,如事务、发布/订阅、Lua脚本和集群等,帮助读者从入门到精通Redis,大幅提升应用性能与可扩展性。
61 0
|
2天前
|
缓存 NoSQL 算法
解决Redis缓存雪崩问题的有效方法
解决Redis缓存雪崩问题的有效方法
9 1
|
1天前
|
缓存 NoSQL 关系型数据库
redis和缓存及相关问题和解决办法 什么是缓存预热、缓存穿透、缓存雪崩、缓存击穿
本文深入探讨了Redis缓存的相关知识,包括缓存的概念、使用场景、可能出现的问题(缓存预热、缓存穿透、缓存雪崩、缓存击穿)及其解决方案。
10 0
redis和缓存及相关问题和解决办法 什么是缓存预热、缓存穿透、缓存雪崩、缓存击穿
|
27天前
|
存储 NoSQL Redis
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
Redis持久化、RDB和AOF方案、Redis主从集群、哨兵、分片集群、散列插槽、自动手动故障转移
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
|
6天前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
21 2
|
10天前
|
存储 缓存 NoSQL
解决Redis缓存击穿问题的技术方法
解决Redis缓存击穿问题的技术方法
30 2
|
10天前
|
缓存 NoSQL Redis
解决 Redis 缓存穿透问题的有效方法
解决 Redis 缓存穿透问题的有效方法
23 2
|
12天前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
12天前
|
开发框架 .NET 中间件
ASP.NET Core Web 开发浅谈
本文介绍ASP.NET Core,一个轻量级、开源的跨平台框架,专为构建高性能Web应用设计。通过简单步骤,你将学会创建首个Web应用。文章还深入探讨了路由配置、依赖注入及安全性配置等常见问题,并提供了实用示例代码以助于理解与避免错误,帮助开发者更好地掌握ASP.NET Core的核心概念。
33 3