MASA Framework 缓存入门与设计
概念
什么是缓存,在项目中,为了提高数据的读取速度,我们会对不经常变更但访问频繁的数据做缓存处理,我们常用的缓存有:
本地缓存
内存缓存:IMemoryCache
Redis: StackExchange.Redis
功能
目前,MasaFramework
为我们提供了以下能力
IDistributedCacheClient: 分布式缓存
Masa.Contrib.Caching.Distributed.StackExchangeRedis: 基于StackExchange.Redis实现的分布式缓存
IMultilevelCacheClient: 多级缓存
Masa.Contrib.Caching.MultilevelCache: 基于内存缓存以及分布式缓存实现的多级缓存,支持监控缓存变更,分布式缓存更新后相应的内存缓存也会同步更新,避免命中过时的内存缓存导致获取错误的数据,同时也尽可能的将多个副本的内存缓存保持同步
入门
前提条件:安装.NET 6.0
分布式缓存
新建 ASP.NET Core 空项目
Assignment.DistributedCache
,并安装Masa.Contrib.Caching.Distributed.StackExchangeRedis
配置
Redis
配置信息
注册分布式缓存,并使用
Redis
缓存,修改Program.cs
使用分布式缓存的数据来源默认为
IOptionsMonitor<RedisConfigurationOptions>
,如果本地未正确在RedisConfig
节点配置缓存信息,且项目中也没有通过其它方式配置使其支持选项模式,则默认使用的 Redis 配置为: 地址: localhost、端口:6379,密码:空,数据库:db0
新建
User
类,用于接收用户信息
如何使用
IDistributedCacheClient
,修改Program.cs
多级缓存
新建 ASP.NET Core 空项目
Assignment.DistributedCache
,并安装Masa.Contrib.Caching.MultilevelCache
、Masa.Contrib.Caching.Distributed.StackExchangeRedis
注册多级缓存,并使用分布式
Redis
缓存,修改Program.cs
新建
User
类,用于接收用户信息
如何使用
IMultilevelCacheClient
,修改Program.cs
测试
借助Postman
或者Swagger
或者使用其它 API 测试工具,分别测试设置缓存与获取缓存,以验证分布式缓存以及多级缓存是可以正常使用的。
友情提示:检查 Redis 缓存,找到刚刚你配置的缓存,确定下它的存储结果是否与你想象的一致!!
规则
经过测试,我们的分布式缓存与多级缓存是可以正常使用的,但查看 Redis 的存储结果后,发现它们实际的存储与我们心目中的结果好像是有点出入,它们分别是:
缓存 Key 不同 (与我们设置的 Key 不完全一致)
结构不同 (实际存储的为 Hash 类型)
内容不同 (内容经过压缩)
缓存 Key 的生成规则
缓存 Key 支持三种规则:
详细规则可查看
存储结构与规则
Masa.Contrib.Caching.Distributed.StackExchangeRedis使用的是 Hash 存储,通过使用 Hash 存储,支持缓存的绝对过期以及相对过期,其中:
内容压缩规则
当存储值类型为以下类型时,不对数据进行压缩:
Byte
SByte
UInt16
UInt32
UInt64
Int16
Int32
Int64
Double
Single
Decimal
当存储值类型为字符串时,对数据进行压缩
当存储值类型不满足以上条件时,对数据进行序列化并进行压缩
分布式 Redis 缓存示例
分布式缓存注册
方案一. 通过本地配置文件注册
修改
appsettings.json
文件
注册分布式 Redis 缓存
方案二. 手动指定 Redis 配置注册
方案三. 通过选项模式注册
通过 Configure 方法使其支持选项模式
注册分布式 Redis 缓存
方案四. 通过指定Configuration
注册
在 Redis 缓存的配置存储到本地
appsettings.json
文件
指定
Configuration
注册分布式 Redis 缓存
方案五. 将配置存储到Dcc上,并通过Configuration提供的手动映射功能,实现选项模式
使用Dcc,并手动指定映射
注册分布式 Redis 缓存
方案三、四、五的本质都是通过支持选项模式来注册分布式 Redis 缓存
修改缓存 Key 映射规则
修改缓存 Key 映射规则十分简单,我们在配置时更改 CacheKeyType 为对应的规则即可,但当 CacheKeyType = 3 需要注意,它需要额外提供类型名与别名的对应关系,完整例子如下:
修改
appsettings.json
, 将 CacheKeyType 的值改为 3
注册分布式缓存并配置类型名与别名的对应关系
通过指定类型与别名的对应关系,从而使得最终形成较短的缓存 Key,以达到节省存储空间的目的,缓存 Key 生成规则可查看
多级缓存示例
多级缓存注册
方案一. 通过本地配置文件注册
修改
appsettings.json
文件,分别配置多级缓存配置以及 Redis 缓存配置
添加多级缓存并使用分布式 Redis 缓存
方案二. 通过手动指定配置
未配置内存缓存时,默认内存缓存永久有效
除了上述两种方式以外,多级缓存的内存缓存配置也同样支持选项模式,我们可以通过Dcc或者利用 builder.Services.Configure<MultilevelCacheOptions>(builder.Configuration)
来支持选项模式
修改缓存 Key 映射规则
源码解读
<a id = "IDistributedCacheClient">IDistributedCacheClient (分布式缓存客户端)</a>
IDistributedCacheClient
接口提供以下方法来处理分布式缓存
以下方法会根据全局缓存 Key 的规则配置以及传入缓存 Key 的规则配置,检测是否需要格式化缓存 Key,对需要格式化 Key 的操作按照缓存 Key 格式化规则进行处理,详细查看:
Get<T>
、GetAsync<T>
: 根据缓存 Key 返回类型为T
的结果 (如果缓存不存在,则返回 Null)GetList<T>
、GetListAsync<T>
: 根据缓存 Key 集合返回对应的缓存值的集合 (针对不存在的缓存 key,其值返回 Null)GetOrSet<T>
、GetOrSetAsync<T>
: 如果在缓存中找到,则返回类型为T
的结果,如果缓存未找到,则执行Setter
,并返回Setter
的结果Set<T>
、SetAsync<T>
: 将指定的缓存 Key 以及缓存值添加到缓存SetList<T>
、SetListAsync<T>
: 将指定的缓存 Key、Value 集合添加缓存Remove<T>
、RemoveAsync<T>
: 将指定的缓存 Key (缓存 Key 集合) 从缓存中移除Refresh<T>
、RefreshAsync<T>
: 刷新指定的缓存 Key (缓存 Key 集合) 的生命周期适用于未被删除、绝对过期时间没有到,但相对过期时间快到的缓存 (延长滑动过期时间)
Exists<T>
、ExistsAsync<T>
: 如果在缓存中找到,则返回 true,否则返回 falseGetKeys<T>
、GetKeysAsync<T>
: 根据 key pattern 得到符合规则的所有缓存 KeyGetByKeyPattern<T>
、GetByKeyPatternAsync<T>
: 根据 key pattern 得到符合规则的所有缓存 Key、Value 集合HashIncrementAsync
: 将指定的缓存 Key 的值增加 Value,并返回增长后的结果HashDecrementAsync
: 将指定的缓存 Key 的值减少 Value,并返回减少后的结果支持设置最小的 Value,避免减少后的值低于设置的最小值,执行失败则返回: -1
KeyExpire<T>
、KeyExpireAsync<T>
: 设置缓存 Key 的生命周期
以下方法不执行缓存 Key 格式化, 应传入缓存完整 Key:
Remove
、RemoveAsync
: 将指定的缓存 Key (缓存 Key 集合) 从缓存中移除Refresh
、RefreshAsync
: 刷新指定的缓存 Key (缓存 Key 集合) 的生命周期适用于未被删除、绝对过期时间没有到,但相对过期时间快到的缓存
Exists
、ExistsAsync
: 如果在缓存中找到,则返回 true,否则返回 falseGetKeys
、GetKeysAsync
: 根据 key pattern 得到符合规则的所有缓存 Key例: 传入 User*,可得到缓存中以 User 开头的所有缓存 Key
KeyExpire
、KeyExpireAsync
: 设置缓存 Key 的生命周期
<a id = "IMultilevelCacheClient">IMultilevelCacheClient (多级缓存客户端)</a>
Get<T>
、GetAsync<T>
: 根据缓存 Key 返回类型为T
的结果 (如果缓存不存在,则返回 Null) (支持监控缓存变更)GetList<T>
、GetListAsync<T>
: 根据缓存 Key 集合返回对应的缓存值的集合 (针对不存在的缓存 key,其值返回 Null)GetOrSet<T>
、GetOrSetAsync<T>
: 如果在缓存中找到,则返回类型为T
的结果,如果缓存未找到,则执行Setter
,并返回Setter
的结果Set<T>
、SetAsync<T>
: 将指定的缓存 Key 以及缓存值添加到缓存SetList<T>
、SetListAsync<T>
: 将指定的缓存 Key、Value 集合添加缓存Remove<T>
、RemoveAsync<T>
: 将指定的缓存 Key (缓存 Key 集合) 从缓存中移除Refresh<T>
、RefreshAsync<T>
: 刷新指定的缓存 Key (缓存 Key 集合) 的生命周期适用于未被删除、绝对过期时间没有到,但相对过期时间快到的缓存 (延长滑动过期时间)
<a id = "IDistributedCacheClient">IDistributedCacheClientFactory (分布式缓存工厂)</a>
Create: 返回指定 Name 的分布式缓存客户端
<a id = "IMultilevelCacheClientFactory">IMultilevelCacheClientFactory (多级缓存工厂)</a>
Create: 返回指定 Name 的多级缓存客户端
如果 Name 为空字符串时,可直接使用
IDistributedCacheClient
或IMultilevelCacheClient
, 默认注册不指定 Name 时,则其 Name 为空字符串,可不通过 Factory 创建
总结
Masa Framework
提供了分布式缓存以及多级缓存的实现,其中有几个优秀的功能:
多级缓存提供了缓存更新后同步更新内存缓存功能
当我们的服务是多副本时,不必担心会缓存更新后其它副本由于内存缓存未过期,导致获取到过期的缓存数据,大大提升我们的用户体验
支持滑动过期以及绝对过期混合使用
避免无用的缓存长时间被持久化,但对于热点数据又可以避免打到 Redis 或者数据库
配置支持热更新,配置更新后同步生效,无需重启项目
缓存 Key 支持格式化,可根据当前缓存值类型与传入缓存 Key 结合形成新的缓存 Key,提高了开发效率以及代码可读性
比如获取用户 id 为 1 的数据,可通过
Client.Get<User>("1")
,而无需:Client.Get<User>("User.1")
本章源码
Assignment16
https://github.com/zhenlei520/MasaFramework.Practice
开源地址
MASA.Framework:https://github.com/masastack/MASA.Framework
如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们
WeChat:MasaStackTechOps
QQ:7424099
版权声明: 本文为 InfoQ 作者【MASA技术团队】的原创文章。
原文链接:【http://xie.infoq.cn/article/91d6837e059d8eba6acd43612】。文章转载请联系作者。
评论