学服装设计学费要多少,宁波seo推广优化怎么做,湛江网站建设推广,西部数码怎么上传网站系列文章目录
链接: 【ASP.NET Core】REST与RESTful详解#xff0c;从理论到实现 链接: 【ASP.NET Core】深入理解Controller的工作机制 链接: 【ASP.NET Core】内存缓存#xff08;MemoryCache#xff09;原理、应用及常见问题解析 文章目录系列文章目录前言一、Redis1.1 …系列文章目录
链接: 【ASP.NET Core】REST与RESTful详解从理论到实现 链接: 【ASP.NET Core】深入理解Controller的工作机制 链接: 【ASP.NET Core】内存缓存MemoryCache原理、应用及常见问题解析 文章目录系列文章目录前言一、Redis1.1 Redis简介1.2 常用数据结构1.3 Redis的持久化1.3.1 RDB1.3.2 AOF1.4 常用应用场景1.4.1 缓存1.4.2 计数器1.4.2 订阅发布二、ASP.NET Core中应用Redis【使用IDistributedCache接口】2.1 安装依赖2.2 Program.cs 注册2.3 IDistributedCache2.4 ASP.NET Core Controller中操作Redis2.4.1 获取缓存2.4.2 设置缓存2.4.3 删除缓存2.4.4 刷新缓存2.4.5 完整代码总结前言
分布式缓存是将缓存数据存储后供多个外部应用服务器中的服务共享使用。比起内存缓存仅支持本服务使用分布式缓存扩展多服务器多应用。故因此得名分布式缓存。本文将介绍ASP.NET Core中如何应用Redis作为分布式缓存服务。 一、Redis
在分享ASP.NET Core中应用Redis作为分布式缓存服务前先简单介绍一下Redis。
1.1 Redis简介
RedisRemote Dictionary Server直译过来就是远程字典服务。作为一款开源的高性能内存数据结构存储系统支持字符串、哈希表、列表等多种数据结构支持持久化保存功能。并且由于数据存储在内存中Redis的读写速度远超传统关系型数据库。
1.2 常用数据结构
字符串String 二进制字符串存储文本、JSON、数字或二进制图片数据等 哈希Hash 键值对集合存储对象结构的数据。 列表List 有序的字符串列表一般用作存储消息队列或者记录时间线。 集合Set 无序且唯一的字符串集合支持交并差操作。因为集合的特性方便去重的场景使用。 有序集合Sorted Set 类似于普通的集合但每个成员都关联了一个分数score一般用作排行榜
1.3 Redis的持久化
Redis的持久化分为两种。一种是RDB通过将内存中的数据快照写入磁盘达到数据的保存另外一种是AOFRedis 将每个写操作追加到 AOF 文件的末尾通过日志的方式记录操作。
1.3.1 RDB
RDB既Redis Database是一种快照持久化机制。是Redis在某一个规则下将某一时刻的内存数据以二进制形式写入磁盘生成RDB文件。
RDB的配置项内容在在Redis根目录下的名为redis.windows-service.conf的文件里。找到如下的结构
save 900 1 # 900秒内至少1个key被修改
save 300 10 # 300秒内至少10个key被修改
save 60 10000 # 60秒内至少10000个key被修改stop-writes-on-bgsave-error yes #当RDB 快照生成过程中发生错误时如磁盘已满、权限不足停止接受新的写操作防止数据不一致默认值yesrdbcompression yes #对RDB文件中的字符串对象启用 LZF 压缩算法rdbchecksum yes #在RDB文件末尾添加 CRC64 校验和用于加载时验证文件完整性dbfilename dump.rdbRDB是默认开启的执行快照存储的时候会在根目录下新建dump.rdb文件记录快照。
1.3.2 AOF
AOF既Append Only File。Redis通过将每个写操作如 SET、INCR追加到 AOF 文件的末尾实现日志的记录。显然这种方式的数据安全性最高。
AOF的配置项内容在在Redis根目录下的名为redis.windows-service.conf的文件里。找到如下的结构
appendonly yesappendfilename appendonly.aofAOF并不是默认开启的。考虑到每一步操作写操作都会记录日志。该生成的日志文件会随着服务的运行变得十分巨大。
1.4 常用应用场景
1.4.1 缓存
将数据库热点数据缓存到 Redis减少数据库访问压力。Redis存储空值得时候会记录NULL自动解决缓存穿透得问题。
1.4.2 计数器
Redis中INCR是用于将存储在指定键中的数值递增 1 的命令。如果键不存在Redis会先将其初始化为 0然后再执行 INCR 操作。由于指令是原子性的这就为我们实现一个计数器提供很好的先决条件。以及接口限流等这种需要使用到计算的功能。
1.4.2 订阅发布
当出现新的报警通知之类的发布消息通知所有订阅的客户端。
二、ASP.NET Core中应用Redis【使用IDistributedCache接口】
在ASP.NET Core中应用Redis还是比较简单的本文应用StackExchangeRedis这个库来对Redis进行操作。
2.1 安装依赖
通过这个指令按照StackExchangeRedis包
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis2.2 Program.cs 注册
在Program.cs中我们通过AddStackExchangeRedisCache这个静态扩展方法注册Redis服务。通过观察AddStackExchangeRedisCache源码我们发现实际上这个扩展方法往DI容器里注册的是IDistributedCache接口以及实现类RedisCacheImpl。生命周期是singleton。
builder.Services.AddStackExchangeRedisCache(options
{options.Configuration builder.Configuration[Redis:ConnectionStrings];options.InstanceName builder.Configuration[Redis:InstanceName];
});/// summary
/// Adds Redis distributed caching services to the specified see crefIServiceCollection /.
/// /summary
/// param nameservicesThe see crefIServiceCollection / to add services to./param
/// param namesetupActionAn see crefAction{RedisCacheOptions}/ to configure the provided
/// see crefRedisCacheOptions/./param
/// returnsThe see crefIServiceCollection/ so that additional calls can be chained./returns
public static IServiceCollection AddStackExchangeRedisCache(this IServiceCollection services, ActionRedisCacheOptions setupAction)
{ArgumentNullThrowHelper.ThrowIfNull(services);ArgumentNullThrowHelper.ThrowIfNull(setupAction);services.AddOptions();services.Configure(setupAction);services.Add(ServiceDescriptor.SingletonIDistributedCache, RedisCacheImpl());return services;
}2.3 IDistributedCache
IDistributedCache是ASP.NET Core框架提供的一个接口用于实现分布式缓存支持多种缓存提供者。也就是说不仅仅是Redis能够通过这个接口被操作。 这个接口定义很简单总的来说就四种方法。GetSetRefreshRemove。以及对应的四个异步方法。
/// summary
/// Represents a distributed cache of serialized values.
/// /summary
public interface IDistributedCache
{/// summary/// Gets a value with the given key./// /summary/// param namekeyA string identifying the requested value./param/// returnsThe located value or null./returnsbyte[]? Get(string key);/// summary/// Gets a value with the given key./// /summary/// param namekeyA string identifying the requested value./param/// param nametokenOptional. The see crefCancellationToken/ used to propagate notifications that the operation should be canceled./param/// returnsThe see crefTask/ that represents the asynchronous operation, containing the located value or null./returnsTaskbyte[]? GetAsync(string key, CancellationToken token default(CancellationToken));/// summary/// Sets a value with the given key./// /summary/// param namekeyA string identifying the requested value./param/// param namevalueThe value to set in the cache./param/// param nameoptionsThe cache options for the value./paramvoid Set(string key, byte[] value, DistributedCacheEntryOptions options);/// summary/// Sets the value with the given key./// /summary/// param namekeyA string identifying the requested value./param/// param namevalueThe value to set in the cache./param/// param nameoptionsThe cache options for the value./param/// param nametokenOptional. The see crefCancellationToken/ used to propagate notifications that the operation should be canceled./param/// returnsThe see crefTask/ that represents the asynchronous operation./returnsTask SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token default(CancellationToken));/// summary/// Refreshes a value in the cache based on its key, resetting its sliding expiration timeout (if any)./// /summary/// param namekeyA string identifying the requested value./paramvoid Refresh(string key);/// summary/// Refreshes a value in the cache based on its key, resetting its sliding expiration timeout (if any)./// /summary/// param namekeyA string identifying the requested value./param/// param nametokenOptional. The see crefCancellationToken/ used to propagate notifications that the operation should be canceled./param/// returnsThe see crefTask/ that represents the asynchronous operation./returnsTask RefreshAsync(string key, CancellationToken token default(CancellationToken));/// summary/// Removes the value with the given key./// /summary/// param namekeyA string identifying the requested value./paramvoid Remove(string key);/// summary/// Removes the value with the given key./// /summary/// param namekeyA string identifying the requested value./param/// param nametokenOptional. The see crefCancellationToken/ used to propagate notifications that the operation should be canceled./param/// returnsThe see crefTask/ that represents the asynchronous operation./returnsTask RemoveAsync(string key, CancellationToken token default(CancellationToken));
}观察以上代码我们发现返回的RedisValue类型都是byte[]字节数组。这是因为分布式缓存通常运行在独立的服务与应用服务器可能使用不同的技术栈。为确保数据能被不同语言或框架正确解析需要一种通用的数据表示形式。这也是IDistributedCache支持多种缓存提供者的原因。
也就是说实际上从分布式缓存里取到的结果从字节数组需要解析成指定格式的数据存储的时候也需要序列化成字节数组。这样操作尤其麻烦好在微软提供了一个名为DistributedCacheExtensions的静态扩展内部帮我们通过 Encoding.UTF8.GetBytes(value)和Encoding.UTF8.GetString(data, 0, data.Length)的形式将结果集和字符串形成转换相当于少转了一步。
DistributedCacheExtensions源码片段【namespace Microsoft.Extensions.Caching.Distributed】
public static Task SetStringAsync(this IDistributedCache cache, string key, string value, DistributedCacheEntryOptions options, CancellationToken token default(CancellationToken))
{ThrowHelper.ThrowIfNull(key);ThrowHelper.ThrowIfNull(value);return cache.SetAsync(key, Encoding.UTF8.GetBytes(value), options, token);
}public static async Taskstring? GetStringAsync(this IDistributedCache cache, string key, CancellationToken token default(CancellationToken))
{byte[]? data await cache.GetAsync(key, token).ConfigureAwait(false);if (data null){return null;}return Encoding.UTF8.GetString(data, 0, data.Length);
}2.4 ASP.NET Core Controller中操作Redis
2.4.1 获取缓存
根据key获取值并且转型 // 尝试从分布式缓存获取数据var cachedData await _distributedCache.GetStringAsync(cacheKey);Movie? movie null;if (!string.IsNullOrEmpty(cachedData)){// 反序列化缓存数据movie JsonSerializer.DeserializeMovie(cachedData);_logger.LogInformation(从缓存中获取了电影数据);}2.4.2 设置缓存 // 缓存未命中从数据源获取movie await _movieAssert.GetMovieAsync(id);if (movie ! null){// 设置缓存选项var cacheOptions new DistributedCacheEntryOptions{// 同时设置绝对过期和滑动过期AbsoluteExpirationRelativeToNow TimeSpan.FromMinutes(10),SlidingExpiration TimeSpan.FromMinutes(5)};// 序列化并存储到分布式缓存var serializedData JsonSerializer.Serialize(movie);await _distributedCache.SetStringAsync(cacheKey, serializedData, cacheOptions);_logger.LogInformation(已将电影数据存入缓存);}2.4.3 删除缓存
根据key删除缓存 await _distributedCache.RemoveAsync(cacheKey);2.4.4 刷新缓存
一般是碰到需要手动续滑动过期时间的场景才会使用。Redis中如果请求了一个被设置了滑动过期时间的缓存会自动刷新滑动过期时间的。 await _distributedCache.RefreshAsync(cacheKey);2.4.5 完整代码
[Route(api/[controller])]
[ApiController]
public class MovieController : ControllerBase
{private readonly ILoggerMovieController _logger;private readonly IMovieAssert _movieAssert;private readonly IDistributedCache _distributedCache;public MovieController(ILoggerMovieController logger, IMovieAssert movieAssert, IDistributedCache distributedCache null){_logger logger;_movieAssert movieAssert;_distributedCache distributedCache;}[HttpGet({id})]public async TaskActionResultMovie? Movies(int id){_logger.LogDebug(开始获取数据);var cacheKey $Movie:{id};// 尝试从分布式缓存获取数据var cachedData await _distributedCache.GetStringAsync(cacheKey);Movie? movie null;if (!string.IsNullOrEmpty(cachedData)){// 反序列化缓存数据movie JsonSerializer.DeserializeMovie(cachedData);_logger.LogInformation(从缓存中获取了电影数据);}else{// 缓存未命中从数据源获取movie await _movieAssert.GetMovieAsync(id);if (movie ! null){// 设置缓存选项var cacheOptions new DistributedCacheEntryOptions{// 同时设置绝对过期和滑动过期AbsoluteExpirationRelativeToNow TimeSpan.FromMinutes(10),SlidingExpiration TimeSpan.FromMinutes(5)};// 序列化并存储到分布式缓存var serializedData JsonSerializer.Serialize(movie);await _distributedCache.SetStringAsync(cacheKey, serializedData, cacheOptions);_logger.LogInformation(已将电影数据存入缓存);}}if (movie is null){return NotFound(没有数据);}return movie;}
}总结
本文介绍了 Redis 的基本情况及在ASP.NET Core 中借助IDistributedCache接口使用Redis作为分布式缓存的具体操作。
IDistributedCache作为微软封装的一个通用的分布式缓存接口只能说应用了Redis的一些基础服务。之后我们会讨论如何通过直接注册ConnectionMultiplexer这种方式获取Redis连接对象使用Redis的那些高级用法。