.NET 中的缓存机制

.NET 缓存机制类型与应用场景

在.NET 中,缓存机制是提升应用性能的关键技术,通过将频繁访问且不常变化的数据(如数据库查询结果、计算结果、API 响应等)暂存在快速存储介质中,减少对原始数据源(如数据库、远程服务)的重复访问,从而降低延迟、减轻服务器压力。

.NET 中的主要缓存类型

根据应用场景和存储位置,.NET 提供了多种缓存方式,核心可分为内存缓存分布式缓存输出缓存三大类。

1. 内存缓存(In-Memory Cache)

定义:将数据存储在应用进程的内存中,仅当前应用实例可访问,适用于单服务器部署的应用。
核心 APIIMemoryCache(.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 应用)。
核心 APIIDistributedCache(.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 应用,减少重复处理相同请求的开销。
核心 APIASP.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);
    }
}

缓存的关键概念

  1. 缓存键(Cache Key):唯一标识缓存项的字符串(如 Product_123),需确保唯一性,避免冲突。
  2. 过期策略
    • 绝对过期:指定时间后强制失效(如 30 分钟后)。
    • 滑动过期:一段时间内未被访问则失效(如 10 分钟内无人访问则删除)。
  3. 缓存穿透 / 击穿 / 雪崩
    • 穿透:查询不存在的数据,缓存无法命中,导致频繁访问数据库。解决:缓存空结果。
    • 击穿:热点数据缓存失效瞬间,大量请求直击数据库。解决:加锁重试、设置永不过期。
    • 雪崩:大量缓存同时失效,数据库压力骤增。解决:过期时间加随机偏移(避免同时失效)。

适用场景总结

缓存类型适用场景优点缺点
内存缓存单服务器应用、本地临时数据、高频访问数据速度快,无序列化开销无法跨实例共享,应用重启失效
分布式缓存多服务器部署(如负载均衡)、共享数据跨实例共享,持久化需序列化,依赖外部存储(如 Redis)
输出缓存Web 应用的 API 接口、视图响应直接缓存 HTTP 响应,减少处理逻辑执行仅适用于 HTTP 场景,灵活性较低

总结

.NET 提供了多种缓存机制,核心目标是通过减少重复计算和数据源访问提升性能。实际开发中需根据部署方式(单实例 / 多实例)、数据特性(是否共享、更新频率)选择合适的缓存类型,并合理配置过期策略,避免缓存一致性问题。内存缓存适合简单场景,分布式缓存适合大规模应用,输出缓存则是 Web 应用的高效优化手段。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值