在.NET 中,缓存机制是提升应用性能的关键技术,通过将频繁访问且不常变化的数据(如数据库查询结果、计算结果、API 响应等)暂存在快速存储介质中,减少对原始数据源(如数据库、远程服务)的重复访问,从而降低延迟、减轻服务器压力。
.NET 中的主要缓存类型
根据应用场景和存储位置,.NET 提供了多种缓存方式,核心可分为内存缓存、分布式缓存和输出缓存三大类。
1. 内存缓存(In-Memory Cache)
定义:将数据存储在应用进程的内存中,仅当前应用实例可访问,适用于单服务器部署的应用。
核心 API:IMemoryCache(.NET Core 及以上内置,需通过依赖注入使用)。
特点:
- 速度极快(内存访问),无需序列化 / 反序列化。
- 生命周期与应用进程绑定(应用重启后缓存失效)。
- 不适合多服务器部署(各实例缓存独立,可能不一致)。
基本用法:
// 1. 注册内存缓存(在Program.cs中)
builder.Services.AddMemoryCache();
// 2. 在服务/控制器中注入使用
public class ProductService
{
private readonly IMemoryCache _cache;
private readonly IProductRepository _repo;
// 构造函数注入
public ProductService(IMemoryCache cache, IProductRepository repo)
{
_cache = cache;
_repo = repo;
}
// 获取产品信息(优先从缓存取,没有则查数据库并缓存)
public async Task<Product> GetProductAsync(int id)
{
// 缓存键(唯一标识缓存项)
string cacheKey = $"Product_{id}";
// 尝试从缓存获取
if (_cache.TryGetValue(cacheKey, out Product product))
{
return product; // 缓存命中,直接返回
}
// 缓存未命中,查询数据库
product = await _repo.GetByIdAsync(id);
if (product == null) return null;
// 设置缓存选项(过期策略)
var cacheOptions = new MemoryCacheEntryOptions()
// 绝对过期:30分钟后自动失效
.SetAbsoluteExpiration(TimeSpan.FromMinutes(30))
// 滑动过期:30分钟内未被访问则失效(避免长期不访问的缓存占用内存)
.SetSlidingExpiration(TimeSpan.FromMinutes(10));
// 存入缓存
_cache.Set(cacheKey, product, cacheOptions);
return product;
}
}
2. 分布式缓存(Distributed Cache)
定义:将数据存储在独立于应用进程的外部存储中(如 Redis、SQL Server、Azure Cache 等),支持多应用实例共享缓存,适用于多服务器部署(如负载均衡的 Web 应用)。
核心 API:IDistributedCache(.NET 内置抽象,需配置具体实现)。
特点:
- 跨实例共享(多服务器可访问同一缓存)。
- 数据持久化(应用重启后缓存不丢失,取决于存储介质)。
- 需序列化 / 反序列化(数据以字节数组存储)。
基本用法(以 Redis 为例):
// 1. 注册 Redis 分布式缓存(Program.cs)
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379"; // Redis 服务器地址
options.InstanceName = "MyApp_"; // 缓存键前缀(避免多应用冲突)
});
// 2. 注入使用
public class OrderService
{
private readonly IDistributedCache _cache;
private readonly IOrderRepository _repo;
public OrderService(IDistributedCache cache, IOrderRepository repo)
{
_cache = cache;
_repo = repo;
}
public async Task<Order> GetOrderAsync(int orderId)
{
string cacheKey = $"Order_{orderId}";
// 从分布式缓存获取(返回字节数组,需反序列化)
byte[] orderBytes = await _cache.GetAsync(cacheKey);
if (orderBytes != null)
{
// 反序列化(需引用 System.Text.Json)
return JsonSerializer.Deserialize<Order>(orderBytes);
}
// 缓存未命中,查数据库
var order = await _repo.GetByIdAsync(orderId);
if (order == null) return null;
// 序列化后存入缓存
byte[] serializedOrder = JsonSerializer.SerializeToUtf8Bytes(order);
// 设置过期时间
var options = new DistributedCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromHours(1));
await _cache.SetAsync(cacheKey, serializedOrder, options);
return order;
}
}
3. 输出缓存(Output Caching)
定义:专门用于缓存 HTTP 响应结果(如 API 接口返回值、MVC 视图),适用于 ASP.NET Core Web 应用,减少重复处理相同请求的开销。
核心 API:ASP.NET Core 7.0+ 内置 IOutputCache,通过特性 [OutputCache] 配置。
基本用法:
// 1. 注册输出缓存(Program.cs)
builder.Services.AddOutputCache();
app.UseOutputCache(); // 启用输出缓存中间件
// 2. 在控制器/接口上使用
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
// 缓存该接口的响应,10分钟内相同请求直接返回缓存结果
[HttpGet("{id}")]
[OutputCache(Duration = 600)] // 缓存600秒(10分钟)
public async Task<IActionResult> GetProduct(int id)
{
// 实际查询逻辑(仅首次请求执行,后续返回缓存)
var product = await _productService.GetByIdAsync(id);
return Ok(product);
}
// 更精细的配置:按参数缓存(不同id分开缓存)
[HttpGet]
[OutputCache(Duration = 300, VaryByQueryKeys = new[] { "category" })]
public async Task<IActionResult> GetByCategory(string category)
{
// 按category参数分别缓存
var products = await _productService.GetByCategoryAsync(category);
return Ok(products);
}
}
缓存的关键概念
- 缓存键(Cache Key):唯一标识缓存项的字符串(如
Product_123),需确保唯一性,避免冲突。 - 过期策略:
- 绝对过期:指定时间后强制失效(如 30 分钟后)。
- 滑动过期:一段时间内未被访问则失效(如 10 分钟内无人访问则删除)。
- 缓存穿透 / 击穿 / 雪崩:
- 穿透:查询不存在的数据,缓存无法命中,导致频繁访问数据库。解决:缓存空结果。
- 击穿:热点数据缓存失效瞬间,大量请求直击数据库。解决:加锁重试、设置永不过期。
- 雪崩:大量缓存同时失效,数据库压力骤增。解决:过期时间加随机偏移(避免同时失效)。
适用场景总结
| 缓存类型 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 内存缓存 | 单服务器应用、本地临时数据、高频访问数据 | 速度快,无序列化开销 | 无法跨实例共享,应用重启失效 |
| 分布式缓存 | 多服务器部署(如负载均衡)、共享数据 | 跨实例共享,持久化 | 需序列化,依赖外部存储(如 Redis) |
| 输出缓存 | Web 应用的 API 接口、视图响应 | 直接缓存 HTTP 响应,减少处理逻辑执行 | 仅适用于 HTTP 场景,灵活性较低 |
总结
.NET 提供了多种缓存机制,核心目标是通过减少重复计算和数据源访问提升性能。实际开发中需根据部署方式(单实例 / 多实例)、数据特性(是否共享、更新频率)选择合适的缓存类型,并合理配置过期策略,避免缓存一致性问题。内存缓存适合简单场景,分布式缓存适合大规模应用,输出缓存则是 Web 应用的高效优化手段。
.NET 缓存机制类型与应用场景

443

被折叠的 条评论
为什么被折叠?



