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

ASP.NET Core - 缓存之分布式缓存

分布式缓存是由多个应用服务器共享的缓存,通常作为访问它的应用服务器的外部服务进行维护。 分布式缓存可以提高 ASP.NET Core 应用的性能和可伸缩性,尤其是当应用由云服务或服务器场托管时。

与其他将缓存数据存储在单个应用服务器上的缓存方案相比,分布式缓存具有多个优势。

当分发缓存数据时,数据:

  • 在多个服务器的请求之间保持一致(一致性)。
  • 在进行服务器重启和应用部署后仍然有效。
  • 不使用本地内存。

1. 分布式缓存的使用

.NET Core 框架下对于分布式缓存的使用是基于 IDistributedCache 接口的,通过它进行抽象,统一了分布式缓存的使用方式,它对缓存数据的存取都是基于 byte[] 的。

IDistributedCache 接口提供以下方法来处理分布式缓存实现中的项:

  • Get、GetAsync:如果在缓存中找到,则接受字符串键并以 byte[] 数组的形式检索缓存项。
  • Set、SetAsync:使用字符串键将项(作为 byte[] 数组)添加到缓存。
  • Refresh、RefreshAsync:根据键刷新缓存中的项,重置其可调到期超时(如果有)。
  • Remove、RemoveAsync:根据字符串键删除缓存项。

使用的时候只需要将其通过容器注入到相应的类中即可。

2. 分布式缓存的接入

分布式缓存是基于特定的缓存应用实现的,需要依赖特定的第三方应用,在接入特定的分布式缓存应用时,需要应用对于的 Nuget 包,微软官方提供了基于 SqlServer 、Redis 实现分布式缓存的 Nuget 包,还推荐了基于 Ncache 的方案,除此之外还有像 Memcache 之类的方案,微软虽然没有提供相应的 Nuget 包,但是社区也有相关开源的项目。

这里只讲 .NET Core 下两种分布式缓存的接入和使用,一种是分布式内存缓存,一种是使用得比较广泛的 Redis。其他的在 .NET Core 框架下的使用是差不多的,仅仅只是接入的时候有点区别。当然,Redis 除了作为分布式缓存来使用,还有其他更加丰富的一些功能,后续也会找时间进行一些介绍。

2.1 基于内存的分布式缓存

分布式内存缓存 (AddDistributedMemoryCache) 是框架提供的 IDistributedCache 实现,用于将项存储在内存中,它就在 Microsoft.Extensions.Caching.Memory Nuget 包中。 分布式内存缓存不是真正的分布式缓存。 缓存项由应用实例存储在运行该应用的服务器上。

分布式内存缓存是一个有用的实现:

  • 在开发和测试场景中。

  • 当在生产环境中使用单个服务器并且内存消耗不重要时。 实现分布式内存缓存会抽象缓存的数据存储。 如果需要多个节点或容错,它允许在未来实现真正的分布式缓存解决方案。

当应用在 Program.cs 的开发环境中运行时,我们可以通过以下方式使用分布式缓存,以下示例代码基于 .NET 控制台程序:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;var host = Host.CreateDefaultBuilder(args).ConfigureServices(services =>{services.AddDistributedMemoryCache();}).Build();host.Run();

之后还是和内存缓存差不多的例子,演示一下缓存的存取、删除、刷新。

public interface IDistributedCacheService
{Task PrintDateTimeNow();
}
public class DistributedCacheService : IDistributedCacheService
{public const string CacheKey = nameof(DistributedCacheService);private readonly IDistributedCache _distributedCache;public DistributedCacheService(IDistributedCache distributedCache){_distributedCache = distributedCache;}public async Task FreshAsync(){await _distributedCache.RefreshAsync(CacheKey);}public async Task PrintDateTimeNowAsync(){var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");var cacheValue = await _distributedCache.GetAsync(CacheKey);if(cacheValue == null){// 分布式缓存对于缓存值的存取都是基于 byte[],所以各种对象必须先序列化为字符串,之后转换为 byte[] 数组cacheValue = Encoding.UTF8.GetBytes(time);var distributedCacheEntryOption = new DistributedCacheEntryOptions(){//AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(20),AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20),SlidingExpiration = TimeSpan.FromSeconds(3)};// 存在基于字符串的存取扩展方法,内部其实也是通过 Encoding.UTF8 进行了编码// await _distributedCache.SetStringAsync(CacheKey, time, distributedCacheEntryOption);await _distributedCache.SetAsync(CacheKey, cacheValue, distributedCacheEntryOption);}time = Encoding.UTF8.GetString(cacheValue);Console.WriteLine("缓存时间:" + time);Console.WriteLine("当前时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));}public async Task RemoveAsync(){await _distributedCache.RemoveAsync(CacheKey);}
}

之后,在入口文件添加以下代码,查看控制台结果是否与预想的一致:

using DistributedCacheSample;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;var host = Host.CreateDefaultBuilder(args).ConfigureServices(services =>{services.AddDistributedMemoryCache();services.AddTransient<IDistributedCacheService, DistributedCacheService>();}).Build();var distributedCache = host.Services.GetRequiredService<IDistributedCacheService>();
// 第一次调用,设置缓存
Console.WriteLine("第一次调用,设置缓存");
await distributedCache.PrintDateTimeNowAsync();
await Task.Delay(TimeSpan.FromSeconds(1));
// 未过滑动时间,数据不变
Console.WriteLine("未过滑动时间,数据不变");
await distributedCache.PrintDateTimeNowAsync();
await Task.Delay(TimeSpan.FromSeconds(3));
// 已过滑动时间,数据改变
Console.WriteLine("已过滑动时间,数据改变");
await distributedCache.PrintDateTimeNowAsync();
await Task.Delay(TimeSpan.FromSeconds(1));
// 未过滑动时间,手动刷新过期时间
Console.WriteLine("未过滑动时间,手动刷新过期时间");
await distributedCache.FreshAsync();
await Task.Delay(TimeSpan.FromSeconds(2));
// 距离上一次调用此方法,已过滑动时间,但由于手动刷新过过期时间,过期时间重新计算,数据不变
Console.WriteLine("距离上一次调用此方法,已过滑动时间,但由于手动刷新过过期时间,过期时间重新计算,数据不变");
await distributedCache.PrintDateTimeNowAsync();
await Task.Delay(TimeSpan.FromSeconds(2));
// 移除缓存
Console.WriteLine("移除缓存");
await distributedCache.RemoveAsync();
// 原有的缓存已移除,调用此方法是重新设置缓存,数据改变
Console.WriteLine("原有的缓存已移除,调用此方法是重新设置缓存,数据改变");
await distributedCache.PrintDateTimeNowAsync();host.Run();

image

结果和预想的是一致的。

2.2 基于 Redis 的分布式缓存

Redis 是一种开源的基于内存的非关系型数据存储,通常用作分布式缓存。在 .NET Core 框架中使用 Redis 实现分布式缓存,需要引用 Microsoft.Extensions.Caching.StackExchangeRedis Nuget 包,包中通过 AddStackExchangeRedisCache 添加 RedisCache 实例来配置缓存实现,该类基于 Redis 实现了 IDistributedCache 接口。

(1) 安装 Redis

这里我在云服务器上通过 Docker 快速安装了 Redis ,映射容器内 Redis 默认端口 6379 到主机端口 6379,并且设置了访问密码为 123456 。

docker run -d --name redis -p 6379:6379 redis --requirepass "123456"

(2) 应用添加依赖包,并且通过配置服务依赖关系

Install-Package Microsoft.Extensions.Caching.StackExchangeRedis

或者通过 VS 的 Nuget 包管理工具进行安装

依赖关系配置如下:

var host = Host.CreateDefaultBuilder(args).ConfigureServices(services =>{// services.AddDistributedMemoryCache();services.AddStackExchangeRedisCache(opyions =>{opyions.Configuration = "xxx.xxx.xxx.xxx:6379,password=123456";});}).Build();

这里只需要将原来的分布式内存缓存服务的配置切换为分布式 Redis 缓存的配置即可,其他的什么都不用改,就可以从内存缓存切换到 Redis 分布式缓存了。所以我们在日常工作的应用搭建中推荐使用基于分布式缓存方案,前期或者开发环境中可以使用基于内存的分布式缓存,后面项目的性能要求高了,可以很方便地切换到真正的分布式缓存,只需改动一行代码。

之后基于前面的例子运行应用,可以看到输出的结果是一样的。

image

而在 Redis 上也可以看得到我们缓存上去的数据。

image

这里还有一个要注意的点,理论上使用分布式缓存是能够增强应用的性能和体验性的,但是像 Redis 这样的分布式缓存一般情况下是和应用部署在不同的服务器,每一次缓存的获取会存在一定的网络传输消耗,当缓存的数据量比较大,而且缓存存取频繁的时候,也会有很大的性能消耗。之前在项目中就遇到过这样的问题,由于一个查询功能需要实时进行计算,计算中需要进行循环,而计算依赖于基础数据,这部分的数据是使用缓存的,当初直接使用 Redis 缓存性能并不理想。当然可以说这种方式是有问题的,但是当时由于业务需要,封装的计算方法中需要在应用启动的时候由外部初始化基础数据,为基础数据能够根据前端改动而刷新,所以用了缓存的方式。

下面是一个示例进行内存缓存和 Redis 缓存的对比:

这里利用 BenchmarkDotNet 进行性能测试,需要先对原有的代码进行一下改造,这里调整了一下构造函数,自行实例化相关缓存的对象,之后有三个方法,分别使用 Redis 缓存、内存缓存、内存缓存结合 Redis 缓存,每个方法中模拟业务中的1000次循环,循环中缓存数据进行存取。

点击查看性能测试代码

 

Program.cs 文件中只保留以下代码:

Summary summary = BenchmarkRunner.Run<DistributedCacheService>();
Console.ReadLine();

测试结果如下:

image

可以看到这种情况下使用 Redis 缓存性能是惨不忍睹的,但是另外两种方式就不一样了。

我们在业务中的缓存最终就是第三种方法的方式,结合内存缓存和 Redis 缓存,根本的思路就是在使用时将数据临时保存在本地,减少网络传输的消耗,并且根据实际业务情况控制内存缓存的超时时间以保持数据的一致性。 

相关文章:

ASP.NET Core - 缓存之分布式缓存

分布式缓存是由多个应用服务器共享的缓存&#xff0c;通常作为访问它的应用服务器的外部服务进行维护。 分布式缓存可以提高 ASP.NET Core 应用的性能和可伸缩性&#xff0c;尤其是当应用由云服务或服务器场托管时。 与其他将缓存数据存储在单个应用服务器上的缓存方案相比&am…...

代理模式(C++)

定义 为其他对象提供一种代理以控制(隔离&#xff0c;使用接口)对这个对象的访问。。 应用场景 在面向对象系统中&#xff0c;有些对象由于某种原因(比如对象创建的开销很大&#xff0c;或者某些操作需要安全控制&#xff0c;或者需要进程外的访问等)直接访问会给使用者、或…...

C# 有效的字母异位词

242 有效的字母异位词 给定两个字符串 和 &#xff0c;编写一个函数来判断 是否是 的字母异位词。stts 注意&#xff1a;若 和 中每个字符出现的次数都相同&#xff0c;则称 和 互为字母异位词。stst 示例 1: 输入: s “anagram”, t “nagaram” 输出: true 示例 2: 输…...

R语言安装包Seurat

环境Ubuntu22&#xff0c;R4.1 also installing the dependencies ‘curl’, ‘openssl’, ‘httr’, ‘plotly’ R包安装的时候报了这个错误ERROR: dependencies httr, plotly are not available for package Seurat 解决方法&#xff0c;退出R&#xff0c;在terminal中键入…...

vue2中使用mixins(混入)和vue3中使用composable

文章目录 一、mixins混入1、 新建mixins文件夹&#xff0c;新建myMixins.js2、myMixins.js 文件3、index.vue 文件&#xff08;要使用的文件&#xff09; mixins 总结二、composable(组合式api composition )1、 新建composables文件夹&#xff0c;新建useEdit.js2、useEdit.js…...

通过OpenTelemetry上报Python-flask应用数据(阿里云)

参考文档 https://help.aliyun.com/document_detail/611711.html?spma2c4g.90499.0.0.34a056ddTu2WWq 先按照 方法一&#xff1a;手动埋点上报Python应用数据 步骤测试上报是否正常。 flas 上报 在 手动埋点上报Python应用数据 的基础上&#xff0c;上报flask应用的数据&#…...

使用node搭建服务器,前端自己写接口,将vue或react打包后生成的dist目录在本地运行

使用node.jsexpress或者使用node.jspm2搭建服务器&#xff0c;将vue或react打包后生成的dist目录在本地运行 vue项目打包后生成的dist目录如果直接在本地打开index.html,在浏览器中会报错&#xff0c;无法运行起来。 通常我是放到后端搭建的服务上面去运行&#xff0c;当时前端…...

一篇文章搞懂如何使用JDBC操作数据库,还有JDBC进阶操作

目录 简介什么是JDBC如何使用JDBC1、获取连接2、操作数据3、关闭连接&#xff0c;释放资源使用技巧 查询操作创建表&#xff0c;插入模拟数据使用Java查询数据的数据SQL注入问题使用PreparedStatement查询 更新操作插入插入并获取主键更新删除 JDBC事务JDBC的批量操作JDBC连接池…...

9.3.2.1网络原理(UDP)

1.UDP的基本特点:无连接,不可靠传输,面向数据报,全双工. 2.1~1024的端口号有特定的含义,不建议使用.比如21:ftp,22:ssh,80:http,443:https. 3.CRC校验算法:循环冗余校验和,把UDP报中的每个字节都依次进行累加,把累加的结果,放到两个字节的变量中,溢出也无所谓,因为都加了一遍.…...

21、stm32使用LTDC驱动LCD

注&#xff1a;本文基于stm32使用FMC驱动SDRAM(IS42S32800G-6BLI)工程继续开发 本例使用安富莱的H743XIH板子驱动LTDC点亮7寸LCD 硬件接线&#xff1a;RGB888 一、cubemx配置 1、LTDC配置 注意此引脚应于上面的硬件接线图一致 2、配置DMA2D 3、背光引脚和触摸引脚 4、时钟…...

合并两个有序链表

就像一个贪吃蛇将两个链表一一的吃进来 class Solution(object):def mergeTwoLists(self, list1, list2):""":type list1: Optional[ListNode]:type list2: Optional[ListNode]:rtype: Optional[ListNode]"""p ListNode(0)cur pwhile list1 a…...

深入了解Unity的Physics类:一份详细的技术指南(七)(上篇)

前言 Unity的Physics类是Unity物理系统的核心&#xff0c;提供了一套用于处理和控制物理模拟的API。这个类提供了用于控制物理系统的全局属性和方法&#xff0c;以及检测和施加力到游戏对象&#xff0c;处理碰撞和触发器事件等。为了让开发者都能更好理解这个Physics类&#x…...

数据结构与算法-数组(附阿里面试题)

一 面试经典&#xff1a; 给你一个文件里面包含全国人民&#xff08;14亿&#xff09;的年龄数据&#xff08;0~180&#xff09;&#xff0c;现在要你统计每一个年龄 有多少人&#xff1f; 给定机器为 单台2CPU2G内存。不得使用现成的容器&#xff0c;比如map等。&am…...

k8s集群网络插件搭建——————解决集群notready(k8s1.20版本,docker24)

前面已经提到&#xff0c;在初始化 k8s-master 时并没有网络相关配置&#xff0c;所以无法跟 node 节点通信&#xff0c;因此状态都是“NotReady”。但是通过 kubeadm join 加入的 node 节点已经在k8s-master 上可以看到。 那么&#xff0c;这个时候我们该怎么办呢&#xff1f;…...

有血有肉的PPT

1、PPT是Powerpoint缩写 2、引申的含义是Powerpoint Power(力量/能量&#xff09; Point(观点/要点) 3、用PPT做的文档是讲演稿&#xff0c;讲演的内容要有力度&#xff0c;之所以要去演讲是为了能够影响受众 4、其次演讲稿上的内容要列出要点、表明观点&#xff0c;所以一般P…...

使用C语言实现UDP消息接收

目录 简介:步骤:步骤 1: 创建套接字步骤 2: 接收消息步骤 3: 完成 函数及变量解释总结: 简介: 在网络通信中&#xff0c;UDP&#xff08;User Datagram Protocol&#xff09;是一种无连接协议&#xff0c;它提供了一种快速、高效的数据传输方法。本文将向您展示如何使用C语言编…...

图片加水印

基础 基于&#xff1a;https://github.com/chishaxie/BlindWaterMark#blindwatermark 前置 安装python&#xff0c;操作系统为ubuntu 18.04.4 server 说明&#xff1a;python2 不行&#xff0c;已验证不行的版本是2.7.17&#xff0c;建议使用ubuntu 18.04.4 server对应的py…...

Nginx代理接口访问返回404

Nginx代理接口访问返回404 一、背景 因为不同业务系统间有接口调用&#xff0c;存在跨域问题&#xff0c;为了解决同源策略&#xff0c;需要将接口通过nginx去转发&#xff0c;但是配置完后通过postman请求一直存在访问404的问题。 访问地址&#xff1a;https://a.test.com/n…...

湘大 XTU OJ 1097 排序 题解:c++ 函数库的使用 快速排序 归并排序 冒泡排序

一、链接 1097 排序 二、题目 Description N个整数&#xff0c;将其排序输出。 输入 第一行是一个整数K&#xff08;1<K<20&#xff09;&#xff0c;表示有多少个样例&#xff0c;每个样例的第一行是一个整数N&#xff08;1<N<1,000&#xff09;和一个字符X&…...

Stable Diffusion AI绘图教学

课程介绍下载 这门课程将教授学生使用Stable Diffusion AI绘图工具进行数据可视化和图形设计。学生将学习基本的绘图原理、数据分析技巧&#xff0c;以及如何使用Stable Diffusion AI创建高质量的图表和可视化作品。通过实践项目和案例研究&#xff0c;学生将提升绘图技能&…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...