缓存在 App 中的应用

缓存(cache)工作原理

说到缓存,我们来看下百度百科的介绍:

  1. 缓存(cache),原始意义是指访问速度比一般 随机存取存储器(RAM) 快的一种 高速存储器,通常它不像系统主存那样使用 DRAM 技术,而使用昂贵但较快速的 SRAM 技术。缓存的设置是所有现代计算机系统发挥高性能的重要因素之一。

    • 动态随机存取存储器(Dynamic Random Access Memory,DRAM
    • 静态随机存取存储器(Static Random-Access Memory,SRAM
  2. 目的:提高数据存取速度(缓存性能优化 万金油 )。

在应用系统中通常会使用到缓存(cache)技术,其中应用系统多级缓存的工作原理大概介绍如下:

说明:在 App 系统中存在多级缓存时,按顺序读取,从一级缓存(Level 1 Cache,简称L1 Cache)逐级往下获取。

项目环境准备

上一篇文章 我们介绍了 .net6 平台的 asp.net core webapi 框架中如何使用 ABP vNext 框架,本篇文章我们继续使用上次创建的 Demo.Abp.WebApplication1 项目,新增如下 NuGet 包文件:

  • Volo.Abp.Caching,本地缓存;
  • Volo.Abp.Caching.StackExchangeRedis,分布式缓存(Redis);

说明:Volo.Abp.Caching.StackExchangeRedis 包已经包含 Volo.Abp.Caching 包。

一、添加 NuGet 包文件

Demo.Abp.WebApplication1 项目中所有的 nuget packages 文件:

说明:在 上篇文章 中,ABP vNext 的这些 nuget packages 文件还未发布 v6.0.0 正式版,生产环境中推荐使用正式稳定版。关于 asp.net core webapi 项目如何遵循 Module(模块化)改造的具体细节,此处不再详细介绍。

添加完成上图的 nuget packages 后,查看 Demo.Abp.WebApplication1.csproj 完整的工程项目文件,如下所示:

<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>net6.0</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings></PropertyGroup><ItemGroup><PackageReference Include="Volo.Abp.AspNetCore" Version="6.0.0" /><PackageReference Include="Volo.Abp.Caching" Version="6.0.0" /><PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" Version="6.0.0" /><PackageReference Include="Volo.Abp.Swashbuckle" Version="6.0.0" /></ItemGroup></Project>

项目结构如下:

二、改造 ApiController 类及相关文件

此处为了模拟业务操作从数据库获取数据,在 WeatherForecastController 控制器中添加一个获取数据的方法:

// 模拟数据库获取数据
private async Task<WeatherForecast> GetWeatherForecastAsync(Guid guid)
{_logger.LogDebug($"{DateTime.Now:G},查询数据库数据...");var index = Random.Shared.Next(-2, 3);var data = new WeatherForecast{Id = Guid.NewGuid(), // WeatherForecast 模型新增 Id 字段Date = DateTime.Now.AddDays(index),TemperatureC = Random.Shared.Next(-20, 55),Summary = Summaries[Random.Shared.Next(Summaries.Length)]};return await Task.FromResult(data);
}

WeatherForecast 模型新增 Id 字段。

namespace Demo.Abp.WebApplication1;public class WeatherForecast
{public Guid Id { get; set; }public DateTime Date { get; set; }public int TemperatureC { get; set; }public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);public string? Summary { get; set; }
}

说明:此处仅说明 WeatherForecastController 控制器新增的部分方法,完整的改造代码后面会展示,尽量展示思路步骤。

ABP vNext 缓存使用

接下来我们分别演示在 asp.net core webapi 框架中如何使用 ABP vNext 提供的缓存包文件:

  • Volo.Abp.Caching,本地缓存;
  • Volo.Abp.Caching.StackExchangeRed,分布式缓存(Redis);

一、本地缓存使用

由于Demo.Abp.WebApplication1 项目是使用默认创建的模式(MiniAPI) ,在 Program.cs 中的 DemoWebApiModule 类声明式添加 Module 化的 NuGet 包依赖,如下所示:

  1. 导入命名空间(Namespace);
using Microsoft.OpenApi.Models;
using Volo.Abp;
using Volo.Abp.AspNetCore;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;
  1. DemoWebApiModule 类声明式添加 Module 化的 NuGet 包依赖;
[DependsOn(typeof(AbpAspNetCoreModule),typeof(AbpCachingModule),typeof(AbpSwashbuckleModule))]
public class DemoWebApiModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){var services = context.Services;services.AddControllers();services.AddEndpointsApiExplorer();services.AddAbpSwaggerGen(options => {options.SwaggerDoc("v1", new OpenApiInfo { Title = "Test DemoWebApiModule API", Version = "v1", Description = "Module 模块化 DemoWebApiModule 自定义类。" });options.DocInclusionPredicate((docName, description) => true);options.CustomSchemaIds(type => type.FullName);options.HideAbpEndpoints(); // 隐藏 ABP vNext 的默认端点});}public override void OnApplicationInitialization(ApplicationInitializationContext context){var app = context.GetApplicationBuilder();var env = context.GetEnvironment();if (env.IsDevelopment()){//app.UseDeveloperExceptionPage();app.UseSwagger();app.UseAbpSwaggerUI(options => {options.SwaggerEndpoint("/swagger/v1/swagger.json", "TestAPI");});}else{app.UseExceptionHandler("/Error");}//app.UseHttpsRedirection();app.UseStaticFiles(); // 不使用静态文件中间件,SwaggerUI将无法渲染UI页面app.UseRouting();app.UseAuthorization();app.UseConfiguredEndpoints(); //代替原来的 app.MapControllers();}
}
  1. WeatherForecastController 控制器中完整代码如下:
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Caching;
using Microsoft.Extensions.Caching.Distributed;namespace Demo.Abp.WebApplication1.Controllers;/// <summary>
/// WeatherForecast
/// </summary>
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{private static readonly string[] Summaries = new[]{"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"};private readonly ILogger<WeatherForecastController> _logger;private readonly IDistributedCache<WeatherForecast> _cache; // 使用 abp vnext 本地缓存// 构造函数 DI 注入本地缓存public WeatherForecastController(ILogger<WeatherForecastController> logger, IDistributedCache<WeatherForecast> cache){_logger = logger;_cache = cache;}// 常规查询数据[HttpGet("/GetList")]public IEnumerable<WeatherForecast> GetDataFromWeatherForecastAsync(){_logger.LogDebug($"{DateTime.Now:G},查询数据库数据...");return Enumerable.Range(1, 5).Select(index => new WeatherForecast{Id = Guid.NewGuid(),Date = DateTime.Now.AddDays(index),TemperatureC = Random.Shared.Next(-20, 55),Summary = Summaries[Random.Shared.Next(Summaries.Length)]}).ToList();}// 使用 ABP vNext 本地缓存查询数据[HttpGet("/Get")]public async Task<WeatherForecast> GetDataFromWeatherForecastAsync(Guid guid) {_logger.LogDebug($"{DateTime.Now:G},查询数据使用本地缓存...");var data = await _cache.GetOrAddAsync(key: guid.ToString(),factory: async () => await GetWeatherForecastAsync(guid),optionsFactory: () => new DistributedCacheEntryOptions{// 添加绝对过期时间,设置 10 秒AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(10)});return data;}// 模拟数据库获取数据private async Task<WeatherForecast> GetWeatherForecastAsync(Guid guid){_logger.LogDebug($"{DateTime.Now:G},查询数据库数据...");var index = Random.Shared.Next(-2, 3);var data = new WeatherForecast{Id = guid,Date = DateTime.Now.AddDays(index),TemperatureC = Random.Shared.Next(-20, 55),Summary = Summaries[Random.Shared.Next(Summaries.Length)]};return await Task.FromResult(data); // 此处仅为了例演示异步方法使用,该方法本身没啥实际意义}
}

1.1 启动项目运行

改造好后,我们习惯性的启动项目运行,验证下是否能成功运行,如下所示:

WeatherForecast 控制器中有两个对外公开的方法,分别是:

  1. /GetList,常规查询(未使用缓存)多条数据。
  2. /Get,使用缓存查询单条数据。

1.2 测试访问接口【/GetList】

1.2.1、curl

curl -X 'GET' \'http://localhost:5220/GetList' \-H 'accept: text/plain' \-H 'RequestVerificationToken: CfDJ8ODjDXixt1tDuxO1cuT_L2xih256N5ivD-oaqHU-qlOmT5DYo778fWPnN-FN9VwU4isJn1azpl9RMoXcaT_GuqD8ICyhdBtSTzizz-W56shntXTF7Uqp2iLUbKwbpURg_imHSk0sTJbF4uM_DGugscE' \-H 'X-Requested-With: XMLHttpRequest'

1.2.2、Request URL,浏览器输入

http://localhost:5220/GetList

1.2.3、响应数据

  • Response body
[{"id": "8b72f7bb-4ff2-449b-bc07-bbe175c0ba65","date": "2022-10-09T19:15:11.1299624+08:00","temperatureC": -15,"temperatureF": 6,"summary": "Chilly"},{"id": "a1606cc5-63ed-4a88-ac83-0d1299b452aa","date": "2022-10-10T19:15:11.130221+08:00","temperatureC": 19,"temperatureF": 66,"summary": "Freezing"},{"id": "3fe5cb1e-5148-49d2-a540-145a0f174abf","date": "2022-10-11T19:15:11.1302229+08:00","temperatureC": 50,"temperatureF": 121,"summary": "Mild"},{"id": "0c7d9b88-7925-4439-a037-81cd1fe08173","date": "2022-10-12T19:15:11.1302232+08:00","temperatureC": 32,"temperatureF": 89,"summary": "Mild"},{"id": "a76cc34b-af1a-421c-9719-742e07029f3a","date": "2022-10-13T19:15:11.1302234+08:00","temperatureC": 53,"temperatureF": 127,"summary": "Hot"}
]
  • Response headers
 content-type: application/json; charset=utf-8  date: Sat,08 Oct 2022 11:15:11 GMT  server: Kestrel  transfer-encoding: chunked

1.3 测试访问接口【/Get】

1.3.1、curl

curl -X 'GET' \'http://localhost:5220/Get?guid=a76cc34b-af1a-421c-9719-742e07029f3a' \-H 'accept: text/plain' \-H 'RequestVerificationToken: CfDJ8ODjDXixt1tDuxO1cuT_L2xih256N5ivD-oaqHU-qlOmT5DYo778fWPnN-FN9VwU4isJn1azpl9RMoXcaT_GuqD8ICyhdBtSTzizz-W56shntXTF7Uqp2iLUbKwbpURg_imHSk0sTJbF4uM_DGugscE' \-H 'X-Requested-With: XMLHttpRequest'

1.3.2、Request URL,浏览器输入

http://localhost:5220/GetList

1.3.3、响应数据

缓存默认设置的 10s 失效时间,在该时间段内多次请求访问,都不会直接操作数据库获取数据,而是从本地进程缓存中获取数据,此时说明我们使用到了 ABP vNetx 提供的 Volo.Abp.Caching 包的功能。

二、分布式缓存使用

2.1 ABP vNext 使用 Redis 默认依赖的 NuGet 包

这里我们使用 Redis 作为分布式缓存服务,ABP vNext 默认使用了 StackExchange.Redis 包,连接字符串同 StackExchange.Redis 的写法,如下所示:

127.0.0.1:6379,defaultDatabase=1,password=Abc...123
# 或者
localhost:6379,defaultDatabase=1,password=Abc...123
# 或者

2.2 准备 Redis-Server 服务

说明:此处使用的 redis 是 docker 环境的容器服务,开放映射端口 6379,因此可以使用【127.0.0.1:6379】或者【localhost:6379】访问。

2.3 测试 Redis-Server 可用性

准备好 Redis-Server 后,使用 Redis 客户端 GUI(这里使用 AnotherRedis desktop manager)工具访问连接,测试下该服务是否正常可用,工具连接如下图所示(说明 redis-server 正常可用):

2.4 修改 appsettings.json 配置文件

接下来在 appsettings.json 文件中添加如下配置:

"Redis": {"IsEnabled": true,"InstanceName": "StackExchangeRedis", // 可省略"Configuration": "localhost:6379,defaultDatabase=1,password=Abc...123" // 未设置密码 password 可以不写
}

2.5 自定义模块类添加 Module 化依赖

最后修改自定义模块 DemoWebApiModule 类,修改代码如下:

using Volo.Abp.Caching.StackExchangeRedis; // 导入 abp vnext 提供的 redis 命名空间 ...[DependsOn(typeof(AbpAspNetCoreModule),typeof(AbpCachingStackExchangeRedisModule), // 声明 Volo.Abp.Caching.StackExchangeRedis 模块依赖typeof(AbpSwashbuckleModule))]
public class DemoWebApiModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){.../* 如果报异常,添加此处配置Configure<RedisCacheOptions>(options => {options.InstanceName = "StackExchangeRedis"; // 该实例名称可自定义});*/}public override void OnApplicationInitialization(ApplicationInitializationContext context){... }
}

说明:“…” 省略的代码配置不变,和使用本地缓存一样即可。

2.6 启动项目测试接口

此处的测试环节和使用本地化缓存的测试一样,不再描述,成功访问接口后,我们使用 redis 可视化管理工具 ——AnotherRedis desktop manager 查看【DB1】里面是否存在对应的 keyvalues,如下图所示:

2.7 使用自定义 RedisModule 模块类

除了使用默认的 AbpCachingStackExchangeRedisModule 模块依赖,还可以自定义MyCachingStackExchangeRedisModule 模块类,该自定义模块类基本 copy 了默认的模块类,只是添加了 options.InstanceName 部分代码,修改如下:

using Microsoft.Extensions.Caching.StackExchangeRedis;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection.Extensions;namespace Demo.Abp.WebApplication1.Moduls;[DependsOn(typeof(AbpCachingModule))]
public class MyCachingStackExchangeRedisModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){IConfiguration configuration = context.Services.GetConfiguration();string redisEnable = configuration["Redis:IsEnabled"];if (!redisEnable.IsNullOrEmpty() && !bool.Parse(redisEnable)){return;}context.Services.AddStackExchangeRedisCache(delegate (RedisCacheOptions options){// 新增部分string redisInstanceName = configuration["Redis:InstanceName"];if (!redisInstanceName.IsNullOrEmpty()){options.InstanceName = redisInstanceName;}string redisConfiguration = configuration["Redis:Configuration"];if (!redisConfiguration.IsNullOrEmpty()){options.Configuration = redisConfiguration;}});context.Services.Replace(ServiceDescriptor.Singleton<IDistributedCache, AbpRedisCache>());}
}

自定义 Module 模块类创建好后,同样地使用 DependsOn 特性显示声明依赖,代码如下所示:

[DependsOn(typeof(AbpAspNetCoreModule),typeof(MyCachingStackExchangeRedisModule), // 声明自定义模块依赖typeof(AbpSwashbuckleModule))]

总结

通过学习 ABP vNext 模块化的缓存(cache)技术,分别提供了 本地化分布式 两种模式的缓存,快速方便的为应用系统接入缓存,局部有效的提升了系统访问性能,当默认提供的分布式缓存服务不满足需求时,还可以自定义扩展分布式缓存模块,对 Module 模块化思想有更近一步的认识。

ABP vNext 缓存使用相关推荐

  1. 基于 abp vNext 和 .NET Core 开发博客项目 - 使用Redis缓存数据

    基于 abp vNext 和 .NET Core 开发博客项目 - 使用Redis缓存数据 转载于:https://github.com/Meowv/Blog 在日志记录中使用的静态方法有人指出写法不 ...

  2. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(五)

    基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(五) 转载于:https://github.com/Meowv/Blog 上篇文章完成了文章详情页数据查询和清除缓存 ...

  3. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(四)

    基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(四) 转载于:https://github.com/Meowv/Blog 上篇文章完成了文章增删改的接口和友情链接列 ...

  4. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三)

    基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三) 转载于:https://github.com/Meowv/Blog 上篇文章完成了分类和标签页面相关的共6个接 ...

  5. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二)

    基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二) 转载于:https://github.com/Meowv/Blog 上篇文章完成了两个接口:文章列表页.文章详 ...

  6. 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(一)

    基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(一) 转载于:https://github.com/Meowv/Blog 现在博客数据库中的数据是比较混乱的,为了看 ...

  7. 基于 abp vNext 和 .NET Core 开发博客项目 - 完善与美化,Swagger登场

    基于 abp vNext 和 .NET Core 开发博客项目 - 完善与美化,Swagger登场 转载于:https://github.com/Meowv/Blog.git 在程序员界,总有一批强迫 ...

  8. 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来

    基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 转载于:https://github.com/Meowv/Blog.git 本篇文章将给项目进行瘦身,删掉对 ...

  9. 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目

    基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 转载于:https://github.com/Meowv/Blog 首先,默认咱们已经有了.net ...

  10. ABP vNext微服务架构详细教程——架构介绍

    总体架构 所有应用服务.API网关.身份认证服务均部署在Kubernetes容器中,由Kubernetes提供应用配置.服务治理.服务监控等功能. 客户端所有访问均通过Kubernetes的Nginx ...

最新文章

  1. Linux内核中关于定时器Timer的应用
  2. 中北大学c语言程序设计作业答案,2016年中北大学软件学院程序设计基础考研复试题库...
  3. H3核心板开发笔记(一):编译及烧写方式
  4. 数据结构之——选择排序
  5. 概率主题模型简介 Introduction to Probabilistic Topic Models
  6. Python 读写当前路径下文件错误 UnboundLocalError: local variable 'file' referenced before assignment
  7. php js vbs,VBScript版的PHP extract()函数
  8. 负债十五万左右,信用卡十万,网贷四五万,怎么上岸?
  9. Spring Framework 3.2 M1发布
  10. php基本语法实验总结,PHP总结(一)基本语法内容
  11. linux 将当前时间往后调整2分钟_【转】修改LINUX时间
  12. 7-110 自动售货机 (30 分)
  13. 双层pdf软件free_这款软件神器,让你读文献的效率翻一倍!(文末有福利哦)...
  14. 【WIN】【C++】遍历文件夹下所有文件
  15. EMC信号完整性落地实测1---走出玄学
  16. SIM868_GNSS结果解析
  17. 《富爸爸,穷爸爸》这本书有何价值?
  18. Intriguing properties of neural networks
  19. 微信卡死代码 java_能让微信卡死的代码是什么 微信整人代码大全
  20. 最近在读的一些文章-2019.05

热门文章

  1. 苹果蒸发639亿 华尔街陷入苹果需求全恐慌模式
  2. 深圳大学计算机专业评级,泰晤士中国学科评级榜单2021 南科大上榜学科全为A
  3. 【随笔】一名蒟蒻的自白
  4. Open vStorage —— 虚拟化的存储路由系统
  5. 凛冬已至:大厂裁员浪潮,基础福利大砍,行业饱和,大龄程序员该如何自处
  6. 犹太人和你想的不一样
  7. Hexo+Github免费搭建个人博客+美化详细教程
  8. java affinity_线程亲和性(Thread Affinity)
  9. 第188篇,想赚钱唯有只争朝夕(扶摇生财思维)
  10. linux驱动与设备实例(字符设备(互斥读写),misc设备和platform_device)