当前位置: 首页 > article >正文

ASP.NET Core 性能优化:内存缓存

文章目录

  • 前言
  • 一、什么是缓存
  • 二、内存缓存
  • 三、使用内存缓存
    • 1)注册内存缓存服务
    • 2)注入与基本使用
    • 3)高级用法
      • GetOrCreate(避免缓存穿透)
      • 异步方法:GetOrCreateAsync(避免缓存穿透)
      • 两种过期策略混用
    • 4)缓存策略配置
    • 5)缓存雪崩
      • 解决方案:
        • ① 缓存过期时间随机化
        • ② 互斥锁控制并发重建
        • ③ 后台定时刷新(永不过期策略)
        • ④ 多级缓存架构
        • ⑤ 熔断降级机制(使用 Polly)
        • ⑥ 缓存预热
        • ⑦ 监控告警
        • 最佳实践建议
    • 6)注意事项
  • 总结


前言

在 .NET Core 中,缓存是性能优化的重要手段之一。

一、什么是缓存

缓存(Caching)是提升应用性能的关键技术,通过存储频繁访问的数据来减少计算和数据库压力。
数据库中的索引等简单有效的优化功能本质上都是缓存。

二、内存缓存

在ASP.NET Core中,内存缓存(Memory Cache)是一种将数据存储在Web服务器内存中的机制,可显著提升应用性能。

三、使用内存缓存

1)注册内存缓存服务

  1. Program.cs中注册服务

    builder.Services.AddMemoryCache();
    

2)注入与基本使用

  1. 通过依赖注入获取IMemoryCache实例

    public class BookService
    {private readonly IMemoryCache _cache;public MyService(IMemoryCache cache){_cache = cache;}
    }
    
  2. 设置缓存项

    // 简单设置
    _cache.Set("key", "value");// 配置过期时间
    var options = new MemoryCacheEntryOptions
    {AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30), // 绝对过期时间SlidingExpiration = TimeSpan.FromMinutes(5)                 // 滑动过期时间
    };
    _cache.Set("key", "value", options);
    
  3. 获取缓存项

    if (_cache.TryGetValue("key", out string value))
    {// 使用value
    }
    
  4. 删除缓存项

    _cache.Remove("key");
    

3)高级用法

GetOrCreate(避免缓存穿透)

  1. 示例
    var data = _cache.GetOrCreate("key", entry =>
    {entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10);//绝对过期策略return GetDataFromDatabase(); // 耗时操作
    });
    

异步方法:GetOrCreateAsync(避免缓存穿透)

  1. 示例
    var data = await _cache.GetOrCreateAsync("key", async entry =>
    {entry.SlidingExpiration = TimeSpan.FromMinutes(5);//滑动过期策略return await FetchDataAsync();
    });
    

两种过期策略混用

  1. 使用滑动过期时间策略,如果一个缓存一致被频繁访问,那么这个缓存项就会一直被续期而不过期。这种情况下可以对一个缓存同时设定滑动过期时间策略和绝对过期时间策略,并且把绝对过期时长设定为大于滑动过期时长,这样缓存项的内容会在绝对过期时间内随着访问被滑动过期续期,但是一旦超过了绝对过期时间缓存项就会被删除

    var data = await _cache.GetOrCreateAsync("key", async entry =>
    {entity.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(100);//绝对过期策略entity.SlidingExpiration=TimeSpan.FromSeconds(10);//滑动过期策略return await FetchDataAsync();
    });
    

4)缓存策略配置

  • 过期策略

    • 绝对过期AbsoluteExpiration/AbsoluteExpirationRelativeToNow
    • 滑动过期SlidingExpiration(每次访问重置时间)

  • 优先级Priority(内存不足时决定清理顺序)

  • 大小限制:通过SizeLimit设置总大小,条目通过Size指定占用量。

    services.AddMemoryCache(options =>
    {options.SizeLimit = 1024; // 总大小(单位自定义)
    });// 设置条目大小
    _cache.Set("key", "value", new MemoryCacheEntryOptions { Size = 1 });
    

5)缓存雪崩

  • 缓存雪崩通常是指大量缓存同时过期,导致请求直接打到数据库,引发数据库压力激增甚至崩溃的情况。

解决方案:

① 缓存过期时间随机化
  1. 通过为缓存项设置基础过期时间并添加随机偏移,分散缓存失效时间。
    var data = await _cache.GetOrCreateAsync("key", async entry =>
    {//设置基础过期时间并添加随机偏移,分散缓存失效时间,从而避免缓存雪崩entity.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(Random.Shared.NextInt64(30,40));//绝对过期策略entity.SlidingExpiration=TimeSpan.FromSeconds(10);//滑动过期策略return await FetchDataAsync();
    });
    
② 互斥锁控制并发重建
  1. 使用 SemaphoreSlim 控制数据库查询并发(分布式环境需改用分布式锁
    public class CacheService
    {private static readonly SemaphoreSlim _cacheLock = new SemaphoreSlim(1, 1);public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan expiration){if (MemoryCache.TryGetValue(key, out T cachedValue))return cachedValue;await _cacheLock.WaitAsync();try{// 二次检查if (MemoryCache.TryGetValue(key, out cachedValue))return cachedValue;var value = await factory();MemoryCache.Set(key, value, expiration.AddRandomJitter());return value;}finally{_cacheLock.Release();}}
    }
    
③ 后台定时刷新(永不过期策略)
  1. 对热点数据采用后台定时刷新机制:

    public class WarmupService : BackgroundService
    {protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){await RefreshHotData();await Task.Delay(TimeSpan.FromMinutes(30), stoppingToken); // 每隔30分钟刷新}}private async Task RefreshHotData(){// 异步更新缓存逻辑}
    }
    
④ 多级缓存架构
  1. 结合内存缓存和分布式缓存
    public class HybridCacheService
    {public async Task<T> GetAsync<T>(string key){// 第一层:内存缓存if (_memoryCache.TryGetValue(key, out T memoryValue))return memoryValue;// 第二层:分布式缓存var distributedValue = await _distributedCache.GetAsync<T>(key);if (distributedValue != null){_memoryCache.Set(key, distributedValue, TimeSpan.FromMinutes(5)); // 短期内存缓存return distributedValue;}// 第三层:数据库return await RefreshCacheFromDb(key);}
    }
    
⑤ 熔断降级机制(使用 Polly)
  1. 配置数据库访问熔断策略
    public void ConfigureServices(IServiceCollection services)
    {var circuitBreakerPolicy = Policy.Handle<SqlException>().CircuitBreakerAsync(exceptionsBeforeBreaking: 3,durationOfBreak: TimeSpan.FromSeconds(30));services.AddHttpClient<IDatabaseService, DatabaseService>().AddPolicyHandler(circuitBreakerPolicy);
    }public class DatabaseService
    {public async Task<Data> GetDataWithFallback(){try{return await GetFromDatabase();}catch (BrokenCircuitException){return GetFallbackData(); // 返回静态默认数据}}
    }
    
⑥ 缓存预热
  1. 应用启动时预加载关键数据
    public class Startup
    {public void Configure(IApplicationBuilder app, IWebHostEnvironment env){app.ApplicationServices.GetService<CacheWarmupper>().Warmup();}
    }public class CacheWarmupper
    {public void Warmup(){Parallel.ForEach(GetCriticalKeys(), key =>{PreloadCache(key);});}
    }
    
⑦ 监控告警
  1. 配置健康检查端点
    services.AddHealthChecks().AddRedis("redis_conn_str", failureStatus: HealthStatus.Degraded).AddSqlServer("db_conn_str");// 在仪表盘监控:
    // - 缓存命中率
    // - 数据库连接数
    // - 错误率
    // - 系统负载
    
最佳实践建议
  1. 分层失效:按数据重要性设置不同过期策略
  2. 动态调整:根据系统负载自动调整缓存时间
  3. 影子Key:设置辅助Key追踪数据访问频率
  4. 请求合并:对批量查询进行合并处理
  5. 降级开关:配置功能开关控制缓存策略

6)注意事项

  • 线程安全IMemoryCache是线程安全的。

  • 内存管理:避免无限制缓存,合理设置过期时间和大小。

  • 数据一致性:数据更新时需手动使缓存失效(Remove或重新Set)。

  • 分布式环境:多服务器部署时,内存缓存无法共享,需改用Redis等分布式缓存。


总结

  • 缓存不可变数据:确保缓存对象不会被修改,或在缓存时创建副本。
  • 监控缓存命中率:评估缓存有效性,调整过期策略。
  • 避免缓存敏感数据:内存数据易失,不适合存储机密信息。

通过合理使用内存缓存,可有效减少数据库压力,提升应用响应速度。

相关文章:

ASP.NET Core 性能优化:内存缓存

文章目录 前言一、什么是缓存二、内存缓存三、使用内存缓存1&#xff09;注册内存缓存服务2&#xff09;注入与基本使用3&#xff09;高级用法GetOrCreate&#xff08;避免缓存穿透&#xff09;异步方法&#xff1a;GetOrCreateAsync&#xff08;避免缓存穿透&#xff09;两种过…...

二战蓝桥杯所感

&#x1f334; 前言 今天是2025年4月12日&#xff0c;第十六届蓝桥杯结束&#xff0c;作为二战的老手&#xff0c;心中还是颇有不甘的。一方面&#xff0c;今年的题目比去年简单很多&#xff0c;另一方面我感觉并没有把能拿的分都拿到手&#xff0c;这是我觉得最遗憾的地方。不…...

屏幕模块解析

通信协议 SPI 引脚定义 GPIO说明引脚配置SCK时钟线推挽输出MOSI主机输出、从机输入推挽输出MISO主机输入、从机输出浮空/上拉输入:没有开启数据传输时为高阻态SS片选推挽输出CPOL时钟极性0:空闲时SCK为低电平 1:空闲时SCK为高电平 CPHA时钟相位0:主从SCK第一个边沿输入1bi…...

查看手机在线状态,保障设备安全运行

手机作为人们日常生活中不可或缺的工具&#xff0c;承载着沟通、工作、娱乐等多种功能。保障手机设备的安全运行是我们每个人都非常重要的任务&#xff0c;而了解手机的在线状态则是其中的一环。通过挖数据平台提供的在线查询工具&#xff0c;我们可以方便快捷地查询手机号的在…...

#关于数据库中的时间存储

✅ 一、是否根据“机器当前时区”得到本地时间再转 UTC&#xff1f; 结论&#xff1a;是的&#xff0c;但仅对 TIMESTAMP 字段生效。 数据库&#xff08;如 MySQL&#xff09;在插入 TIMESTAMP 类型数据时&#xff1a; 使用当前会话的时区&#xff08;默认跟随系统时区&#…...

第16届蓝桥杯省赛python B组个人题解

文章目录 前言ABCDEFGH 前言 仅个人回忆&#xff0c;不保证正确性 貌似都是典题&#xff0c;针对python的长代码模拟题也没有&#xff0c;一小时速通了&#xff0c;希望不要翻车。 更新&#xff1a;B、G翻车了。。 A 答案&#xff1a;103 B 应该是按长度排序&#xff0c;然后…...

lvs+keepalived+dns高可用

1.配置dns相关服务 1.1修改ip地址主机名 dns-master: hostnamectl hostname lvs-master nmcli c modify ens160 ipv4.method manual ipv4.addresses 10.10.10.107/24 ipv4.gateway 10.10.10.2 ipv4.dns 223.5.5.5 connection.autoconnect yes nmcli c up ens160dns-salve: h…...

Spark RDD相关概念

Spark运行架构与核心组件 1.Spark运行梁构 spark运行架构包括master和slave两个主要部分。master负责管理整个集群的作业任务调度&#xff0c;而slave则负责实际执行任务。 dirver是Spark驱动器节点&#xff0c;负责执行Spark任务中的main方法&#xff0c;将用户程序转换成作业…...

雷池WAF防火墙如何构筑DDoS防护矩阵?——解读智能语义解析对抗新型流量攻击

本文深度解析雷池WAF防火墙在DDoS攻防中的技术突破&#xff0c;通过智能语义解析、动态基线建模、协同防护体系三大核心技术&#xff0c;实现从流量特征识别到攻击意图预判的进化。结合2023年金融行业混合攻击防御案例&#xff0c;揭示新一代WAF如何通过协议级漏洞预判与AI行为…...

网络互连与互联网

1.在路由表中找不到目标网络时使用默认路由&#xff0c;默认路由通常指本地网关的地址。 2.OSPF最主要的特征是使用分布式链路状态协议&#xff0c;而RIP使用的是距离向量协议。 3.OSPF使用链路状态公告LSA扩散路由信息 4.内部网关路由协议IGRP是一种动态距离矢量路由协议&a…...

Pytorch实现基于FlowS-Unet的遥感图像建筑物变化检测方法

基于FlowS-Unet的遥感图像建筑物变化检测方法是一种结合深度学习与细化结构的先进技术,旨在提高建筑物变化检测的精度和鲁棒性。 一、FlowS-Unet的核心架构与原理 FlowS-Unet是在经典U-Net网络基础上改进的模型,主要引入了超列(Hypercolumns)和FlowNet细化结构,通过多尺…...

什么是柜台债

柜台债&#xff08;柜台债券业务&#xff09;是指通过银行等金融机构的营业网点或电子渠道&#xff0c;为投资者提供债券买卖、托管、结算等服务的业务模式。它允许个人、企业及机构投资者直接参与银行间债券市场的交易&#xff0c;打破了以往仅限机构参与的壁垒。以下是综合多…...

SD + Contronet,扩散模型V1.5+约束条件后续优化:保存Canny边缘图,便于视觉理解——stable diffusion项目学习笔记

目录 前言 背景与需求 代码改进方案 运行过程&#xff1a; 1、Run​编辑 2、过程&#xff1a; 3、过程时间线&#xff1a; 4、最终效果展示&#xff1a; 总结与展望 前言 机器学习缺点之一&#xff1a;即不可解释性。最近&#xff0c;我在使用stable diffusion v1.5 Co…...

【ROS2】行为树:BehaviorTree

1、简介 与状态机不同,行为树强调执行动作,而不是状态之间的转换。 行为树是可组合的。可以重复使用简单的行为来构建复杂的行为。 在游戏领域,行为树已经比较流行了。主要用于维护游戏角色的各种动作和状态。 ROS2的导航框架Navigation2中引入了行为树来组织机器人的工作流…...

《JVM考古现场(十八):造化玉碟·用字节码重写因果律的九种方法》

"鸿蒙初判&#xff01;当前因果链突破十一维屏障——全体码农修士注意&#xff0c;《JVM考古现场&#xff08;十八&#xff09;》即将渡劫飞升&#xff01;" 目录 上卷阴阳交缠 第一章&#xff1a;混沌初开——JVM因果律的量子纠缠 第二章&#xff1a;诛仙剑阵改—…...

使用nuxt3+tailwindcss4+@nuxt/content3在页面渲染 markdown 文档

nuxt3tailwindcss在页面渲染 markdown 文档 页面效果 依赖 “nuxt/content”: “^3.4.0” “tailwindcss”: “^4.0.10” “nuxt”: “^3.16.2” “tailwindcss/vite”: “^4.0.10” tailwindcss/typography (这个是格式化 md 样式用的) 注意&#xff1a; 这里nuxt/content…...

[250412] OpenSSH 10.0 发布,移除DSA算法,sshd默认禁用有限域DH,并分离认证代码

目录 OpenSSH 10.0 正式发布&#xff1a;关键更新摘要主要变更亮点&#xff08;潜在不兼容性&#xff09; OpenSSH 10.0 正式发布&#xff1a;关键更新摘要 OpenSSH 10.0 已于 2025 年 4 月 9 日发布&#xff0c;现在可以从官网列出的镜像站点获取最新版本。 OpenSSH 是一个广…...

部署NFS版StorageClass(存储类)

部署NFS版StorageClass存储类 NFS版PV动态供给StorageClass(存储类)基于NFS实现动态供应下载NFS存储类资源清单部署NFS服务器为StorageClass(存储类)创建所需的RBAC部署nfs-client-provisioner的deployment创建StorageClass使用存储类创建PVC NFS版PV动态供给StorageClass(存储…...

JS【详解】迭代器 Iterator(含可迭代对象、同步迭代器、异步迭代器等)

什么是迭代器&#xff1f; JS 迭代器是一种遍历访问数据结构中所有成员的机制&#xff0c;本质是一个指针对象。 为什么要有迭代器&#xff1f; 为各种不同的数据结构提供统一的访问机制。自定义数据结构的遍历&#xff1a;当你创建了一个自定义的数据结构时&#xff0c;可以实…...

CFS 调度器两种调度类型普通调度 和 组调度

在 Linux 的 CFS&#xff08;Completely Fair Scheduler&#xff09; 调度器中&#xff0c;确实存在两种调度类型&#xff1a;普通调度 和 组调度。这两种调度类型分别适用于不同的场景&#xff0c;并通过三个关键维度&#xff08;权重、抢占优先级、最大配额&#xff09;来影响…...

Linux网络编程——详解网络层IP协议、网段划分、路由

目录 一、前言 二、IP协议的认识 1、什么是IP协议&#xff1f; 2、IP协议报头 三、网段划分 1、初步认识IP与路由 2、IP地址 I、DHCP动态主机配置协议 3、IP地址的划分 I、CIDR设计 II、子网数目的计算 III、子网掩码的确定 四、特殊的IP地址 五、IP地址的数量限…...

【图像生成之21】融合了Transformer与Diffusion,Meta新作Transfusion实现图像与语言大一统

论文&#xff1a;Transfusion: Predict the Next Token and Diffuse Images with One Multi-Modal Model 地址&#xff1a;https://arxiv.org/abs/2408.11039 类型&#xff1a;理解与生成 Transfusion模型‌是一种将Transformer和Diffusion模型融合的多模态模型&#xff0c;旨…...

Microsoft Office 如何启用和正常播放 Flash 控件

对于新安装的 Office 默认是不支持启用 Flash 组件的&#xff0c;Flash 组件会无法播放或者黑屏。 本片文章就带你解决这个问题&#xff0c;相关资料都在下方连接内。前提概要&#xff0c;教程对应的版本是 mso16&#xff0c;即 Office 2016 及更新版本&#xff0c;以及 365 等…...

深入浅出:信号灯与系统V信号灯的实现与应用

深入浅出&#xff1a;信号灯与系统V信号灯的实现与应用 信号灯&#xff08;Semaphore&#xff09;是一种同步机制&#xff0c;用于控制对共享资源的访问。在多线程或多进程环境下&#xff0c;信号灯能够帮助协调多个执行单元对共享资源的访问&#xff0c;确保数据一致性与程序…...

定位改了IP属地没变怎么回事?一文解析

明明用虚拟定位软件将手机位置改到了“三亚”&#xff0c;为何某某应用评论区显示的IP属地还是“北京”&#xff1f;为什么切换了代理IP&#xff0c;平台却似乎“无视”这一变化&#xff1f; 在“IP属地显示”功能普及后&#xff0c;许多用户尝试通过技术手段隐藏真实位置&…...

Cygwin中使用其它平台生成的动态库

在 Cygwin 环境下链接 VC 生成的 DLL 库需解决符号导出格式和调用约定的兼容性问题&#xff0c;以下是具体操作步骤&#xff1a; 一、VC 生成 DLL 的配置要点 ‌声明 C 风格导出函数‌ 在 VC 中使用 extern "C" 和 __declspec(dllexport) 避免 C 名称修饰&#xff0c…...

《深入理解生命周期与作用域:以C语言为例》

&#x1f680;个人主页&#xff1a;BabyZZの秘密日记 &#x1f4d6;收入专栏&#xff1a;C语言 &#x1f30d;文章目入 一、生命周期&#xff1a;变量的存在时间&#xff08;一&#xff09;生命周期的定义&#xff08;二&#xff09;C语言中的生命周期类型&#xff08;三&#…...

算法魅力揭秘:螺旋矩阵 II 的模拟填充与规则总结

算法魅力揭秘&#xff1a;螺旋矩阵 II 的模拟填充与规则总结 作为一个算法人&#xff0c;我们经常在竞赛和面试中遇到各种“矩阵类”问题&#xff0c;而螺旋矩阵 II 是其中一颗耀眼的明星。今天我将带大家从直观理解到实战代码&#xff0c;全面拆解螺旋矩阵 II 的规律与实现。…...

一个插件,免费使用所有顶级大模型(Deepseek,Gpt,Grok,Gemini)

DeepSider是一款集成于浏览器侧边栏的AI对话工具&#xff0c;可免费使用所有顶级大模型 包括GPT-4o&#xff0c;Grok3,Claude 3.5 Sonnet,Claude 3.7,Gemini 2.0&#xff0c;Deepseek R1满血版等 以极简交互与超快的响应速度&#xff0c;完成AI搜索、实时问答、内容创作、翻译、…...

springboot Filter实现请求响应全链路拦截!完整日志监控方案​​

一、为什么你需要这个过滤器&#xff1f;​​ 日志痛点&#xff1a; &#x1f6a8; 请求参数散落在各处&#xff1f; &#x1f6a8; 响应数据无法统一记录&#xff1f; &#x1f6a8; 日志与业务代码严重耦合&#xff1f; ​​解决方案​​&#xff1a; 一个Filter同时拦截请…...