在.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 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 GetOrderAsync(int orderId)

{

string cacheKey = $"Order_{orderId}";

// 从分布式缓存获取(返回字节数组,需反序列化)

byte[] orderBytes = await _cache.GetAsync(cacheKey);

if (orderBytes != null)

{

// 反序列化(需引用 System.Text.Json)

return JsonSerializer.Deserialize(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 GetProduct(int id)

{

// 实际查询逻辑(仅首次请求执行,后续返回缓存)

var product = await _productService.GetByIdAsync(id);

return Ok(product);

}

// 更精细的配置:按参数缓存(不同id分开缓存)

[HttpGet]

[OutputCache(Duration = 300, VaryByQueryKeys = new[] { "category" })]

public async Task 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 应用的高效优化手段。