关于我

作者博客|文章首发

缓存基础知识

缓存可以减少生成内容所需的工作,从而显著提高应用程序的性能和可伸缩性。 缓存最适用于不经常更改的 数据,生成 成本很高。 通过缓存,可以比从数据源返回的数据的副本速度快得多。 应该对应用进行编写和测试,使其 永不 依赖于缓存的数据。

ASP.NET Core 支持多个不同的缓存。 最简单的缓存基于 IMemoryCache。 IMemoryCache 表示存储在 web 服务器的内存中的缓存。 在服务器场上运行的应用 (多台服务器) 应确保会话在使用内存中缓存时处于粘滞状态。 粘滞会话确保来自客户端的后续请求都将发送到相同的服务器。

内存中缓存可以存储任何对象。 分布式缓存接口仅限 byte[] 。 内存中和分布式缓存将缓存项作为键值对。

缓存指南

  • 代码应始终具有回退选项,以获取数据,而 是依赖于可用的缓存值。
  • 缓存使用稀有资源内存,限制缓存增长:
    • 不要 使用外部 输入作为缓存键。
    • 使用过期限制缓存增长。
    • 使用 SetSize、Size 和 SizeLimit 限制缓存大小]。 ASP.NET Core 运行时不会根据内存 压力限制缓存 大小。 开发人员需要限制缓存大小。

使用

DI注入

创建一个NetCore控制台项目,进行缓存的项目演示。

控制台项目只有一个初始化的Program.cs文件。基于NetCore进行项目编码,每一步就是创建一个基础模板,使用依赖注入的方式。

nuget install Microsoft.Extensions.Hosting
  public static class Program
{
static async void Main(string[] args)
{
var builder = new HostBuilder().ConfigureServices((context, service) =>
{ }); await builder.RunConsoleAsync();
}
}

注入缓存服务,控制台需要下载库 Microsoft.Extensions.Caching.Memory

nuget install Microsoft.Extensions.Caching.Memory
  public static class Program
{
static async void Main(string[] args)
{
var builder = new HostBuilder().ConfigureServices((context, service) =>
{
service.AddMemoryCache(); service.AddScoped<CacheService>();//实际测试服务 service.AddHostedService<BackgroundJob>();//后台执行方法
}); await builder.RunConsoleAsync();
}
}

后台服务

public class BackgroundJob : IHostedService
{
private readonly CacheService _cacheService; public BackgroundJob(CacheService cacheService)
{
_cacheService = cacheService;
} public Task StartAsync(CancellationToken cancellationToken)
{
_cacheService.Action(); return Task.CompletedTask;
} public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

MemoryCache使用总结

通过构造函数自动注入IMemoryCache

public class CacheService
{
private readonly IMemoryCache _memoryCache; public CacheService(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
}

最基本的使用

Set方法根据Key设置缓存,默认缓存不过期

Get方法根据Key取出缓存

/// <summary>
/// 缓存设置
/// </summary>
public void BaseCache()
{
string cacheKey = "timestamp";
//set cache
_memoryCache.Set(cacheKey, DateTime.Now.ToString()); //get cache
Console.WriteLine(_memoryCache.Get(cacheKey));
}

IMemoryCache提供一些好的语法糖供开发者使用,具体内容看下方文档

/// <summary>
/// 特殊方法的使用
/// </summary>
public void ActionUse()
{
//场景-如果缓存存在,取出。如果缓存不存在,写入
//原始写法
string cacheKey = "timestamp";
if (_memoryCache.Get(cacheKey) != null)
{
_memoryCache.Set(cacheKey, DateTime.Now.ToString());
}
else
{
Console.WriteLine(_memoryCache.Get(cacheKey));
} //新写法
var dataCacheValue = _memoryCache.GetOrCreate(cacheKey, entry =>
{
return DateTime.Now.ToString();
});
Console.WriteLine(dataCacheValue); //删除缓存
_memoryCache.Remove(cacheKey); //场景 判断缓存是否存在的同时取出缓存数据
_memoryCache.TryGetValue(cacheKey, out string cacheValue);
Console.WriteLine(cacheValue); }

缓存过期策略

设置缓存常用的方式主要是以下二种

  1. 绝对到期(指定在一个固定的时间点到期)
  2. 滑动到期(在一个时间长度内没有被命中则过期)
  3. 组合过期 (绝对过期+滑动过期)

绝对到期

过期策略 5秒后过期

//set absolute cache
string cacheKey = "absoluteKey";
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), TimeSpan.FromSeconds(5)); //get absolute cache
for (int i = 0; i < 6; i++)
{
Console.WriteLine(_memoryCache.Get(cacheKey));
Thread.Sleep(1000);
}

滑动到期

过期策略 2秒的滑动过期时间,如果2秒内有访问,过期时间延后。当2秒的区间内没有访问,缓存过期

//set slibing cache
string cacheSlibingKey = "slibingKey";
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
options.SlidingExpiration = TimeSpan.FromSeconds(2); _memoryCache.Set(cacheSlibingKey, DateTime.Now.ToString(), options); //get slibing cache
for (int i = 0; i < 2; i++)
{
Console.WriteLine(_memoryCache.Get(cacheSlibingKey));
Thread.Sleep(1000);
}
for (int i = 0; i < 2; i++)
{
Thread.Sleep(2000);
Console.WriteLine(_memoryCache.Get(cacheSlibingKey));
}

组合过期

过期策略

6秒绝对过期+2秒滑动过期

满足任意一个缓存都将失效

string cacheCombineKey = "combineKey";
MemoryCacheEntryOptions combineOptions = new MemoryCacheEntryOptions();
combineOptions.SlidingExpiration = TimeSpan.FromSeconds(2);
combineOptions.AbsoluteExpiration = DateTime.Now.AddSeconds(6); _memoryCache.Set(cacheCombineKey, DateTime.Now.ToString(), combineOptions); //get slibing cache
for (int i = 0; i < 2; i++)
{
Console.WriteLine(_memoryCache.Get(cacheCombineKey));
Thread.Sleep(1000);
} for (int i = 0; i < 6; i++)
{
Thread.Sleep(2000);
Console.WriteLine(i+"|" + _memoryCache.Get(cacheCombineKey));
} Console.WriteLine("------------combineKey End----------------");

缓存状态变化事件

当缓存更新、删除时触发一个回调事件,记录缓存变化的内容。

/// <summary>
/// cache状态变化回调
/// </summary>
public void CacheStateCallback()
{
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
options.AbsoluteExpiration = DateTime.Now.AddSeconds(3
);
options.RegisterPostEvictionCallback(MyCallback, this); //show callback console
string cacheKey = "absoluteKey";
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), options); Thread.Sleep(500);
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), options); _memoryCache.Remove(cacheKey); } private static void MyCallback(object key, object value, EvictionReason reason, object state)
{
var message = $"Cache entry state change:{key} {value} {reason} {state}";
((CacheService)state)._memoryCache.Set("callbackMessage", message); Console.WriteLine(message);
}

缓存依赖策略

设置一个缓存A

设置一个缓存B,依赖于缓存A 如果缓存A失效,缓存B也失效

/// <summary>
/// 缓存依赖策略
/// </summary>
public void CacheDependencyPolicy()
{
string DependentCTS = "DependentCTS";
string cacheKeyParent = "CacheKeys.Parent";
string cacheKeyChild = "CacheKeys.Child"; var cts = new CancellationTokenSource();
_memoryCache.Set(DependentCTS, cts); //创建一个cache策略
using (var entry = _memoryCache.CreateEntry(cacheKeyParent))
{
//当前key对应的值
entry.Value = "parent" + DateTime.Now; //当前key对应的回调事件
entry.RegisterPostEvictionCallback(MyCallback, this); //基于些key创建一个依赖缓存
_memoryCache.Set(cacheKeyChild, "child" + DateTime.Now, new CancellationChangeToken(cts.Token));
} string ParentCachedTime = _memoryCache.Get<string>(cacheKeyParent);
string ChildCachedTime = _memoryCache.Get<string>(cacheKeyChild);
string callBackMsg = _memoryCache.Get<string>("callbackMessage");
Console.WriteLine("第一次获取");
Console.WriteLine(ParentCachedTime + "|" + ChildCachedTime + "|" + callBackMsg); //移除parentKey
_memoryCache.Get<CancellationTokenSource>(DependentCTS).Cancel();
Thread.Sleep(1000); ParentCachedTime = _memoryCache.Get<string>(cacheKeyParent);
ChildCachedTime = _memoryCache.Get<string>(cacheKeyChild);
callBackMsg = _memoryCache.Get<string>("callbackMessage");
Console.WriteLine("第二次获取");
Console.WriteLine(ParentCachedTime + "|" + ChildCachedTime + "|" + callBackMsg);
}

参考资料

AspNetCore中的缓存内存

.NetCore缓存篇之MemoryCache

Asp.Net Core 轻松学-在.Net Core 使用缓存和配置依赖策略

拥抱.NET Core系列:MemoryCache 缓存过期

推荐阅读

Redis工具收费后新的开源已出现

GitHub上Star最高的工程师技能图谱

中国程序员最容易发错的单词

推荐!!! Markdown图标索引网站

最后

本文到此结束,希望对你有帮助

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

更多精彩技术文章汇总在我的 公众号【程序员工具集】,持续更新,欢迎关注订阅收藏。

NetCore的缓存使用详例的更多相关文章

  1. Redis for Windows(C#缓存)配置文件详解

    Redis for Windows(C#缓存)配置文件详解   前言 在上一篇文章中主要介绍了Redis在Windows平台下的下载安装和简单使用http://www.cnblogs.com/aehy ...

  2. 《深入理解mybatis原理6》 MyBatis的一级缓存实现详解 及使用注意事项

    <深入理解mybatis原理> MyBatis的一级缓存实现详解 及使用注意事项 0.写在前面   MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓 ...

  3. 浏览器 HTTP 协议缓存机制详解

    最近在准备优化日志请求时遇到了一些令人疑惑的问题,比如为什么响应头里出现了两个 cache control.为什么明明设置了 no cache 却还是发请求,为什么多次访问时有时请求里带了 etag, ...

  4. nginx平台初识(二) 浏览器 HTTP 协议缓存机制详解

    1.缓存的分类 缓存分为服务端侧(server side,比如 Nginx.Apache)和客户端侧(client side,比如 web browser). 服务端缓存又分为 代理服务器缓存 和 反 ...

  5. PHP缓存机制详解

    一,PHP缓存机制详解 我们可以使用PHP自带的缓存机制来完成页面静态化,但是仅靠PHP自身的缓存机制并不能完美的解决页面静态化,往往需要和其他静态化技术(通常是伪静态技术)结合使用. output ...

  6. 二,PHP缓存机制详解

    一,PHP缓存机制详解 我们可以使用PHP自带的缓存机制来完成页面静态化,但是仅靠PHP自身的缓存机制并不能完美的解决页面静态化,往往需要和其他静态化技术(通常是伪静态技术)结合使用. output ...

  7. hibernate缓存机制详解

    hiberante面试题—hibernate缓存机制详解   这是面试中经常问到的一个问题,可以按照我的思路回答,准你回答得很完美.首先说下Hibernate缓存的作用(即为什么要用缓存机制),然后再 ...

  8. Robocopy.exe使用详例

    Robocopy.exe使用详例           Robocopy.exe 是 微软在Windows server 2003 Resource Kit Tools 里面提供的程序来做备份的.Vis ...

  9. 浏览器 HTTP 协议缓存机制详解--网络缓存决策机制流程图

    1.缓存的分类 2.浏览器缓存机制详解 2.1 HTML Meta标签控制缓存 2.2 HTTP头信息控制缓存 2.2.1 浏览器请求流程 2.2.2 几个重要概念解释 3.用户行为与缓存 4.Ref ...

随机推荐

  1. Gatsby Themes

    Gatsby Themes React & SSR gatsby-config.js refs https://www.gatsbyjs.com/docs/themes/ https://ww ...

  2. Learn-JavaScript-with-MDN 系列文章: 01. var & let & const 对比

    Learn-JavaScript-with-MDN 系列文章: 01. var & let & const 对比 var & let & const 区别 https: ...

  3. js字典

    传送门https://www.2cto.com/kf/201709/680989.html 点击

  4. go-admin在线开发平台学习-3[细节解析]

    本章节主要的内容是对go-admin中的一些有趣编码进行分析,为自己以后提供一些借鉴 使用cli方式启动项目 使用cobra[眼镜蛇]完成强壮cli的工具,确保稳定. 使用cli的方式启动项目的好处显 ...

  5. sublime 使用过程中遇到的问题

    1.当我把鼠标放置在下图所示的class上几秒钟后,sublime就会在全局查找当前的class字符,这时sublime就会出现卡顿或无响应 解决方法: 点击preferences下的settings ...

  6. 从微信小程序到鸿蒙js开发【12】——storage缓存&自动登录

    鸿蒙入门指南,小白速来!从萌新到高手,怎样快速掌握鸿蒙开发?[课程入口] 正文: 在应用开发时,我们常需要将一些数据缓存到本地,以提升用户体验.比如在一个电商的app中,如果希望用户登录成功后,下次打 ...

  7. oracle 中的左外连接、右外连接、全连接

    左外连接 左外连接 全连接1.左外连接:表1 left [outer] join 表1 on 条件 在等值连接的基础上会把表1中的其他内容也展示出来 而表2只会显示符合条件的内容 . outer 可省 ...

  8. FTP服务器搭建以及上传下载的学习

    首先需要搭建FTP服务步骤如下: 1.在win7上先开启ftp服务:这里点击确定后,可能会要等一会儿,完成后有时系统会提示重启 2.打开   计算机-->管理-->   在这里我们可以看见 ...

  9. 完整的 LDAP + phpLDAPadmin安装部署流程 (ubuntu18.04)

    LDAP 安装部署以及基础使用 因工作需求需要使用ldap管理用户权限,在踩了一系列坑之后,总结了一些流畅的文档,希望可以帮到和曾经的我一样迷茫的人. 基础环境:Ubuntu 18.04 一.安装 r ...

  10. windows server 2008 r2 AD域服务器设置

    域控制器是指在"域"模式下,至少有一台服务器负责每一台联入网络的电脑和用户的验证工作,相当于一个单位的门卫一样,称为"域控制器(Domain Controller,简写为 ...