在 .NET Core 中实现缓存端模式:利用 Redis 提升性能

打印 上一主题 下一主题

主题 916|帖子 916|积分 2748

 

在今世的 Web 应用中,缓存是提升应用性能的关键组件。尤其是当应用频仍读取数据时,利用缓存可以显著淘汰数据库的负担并提高相应速率。缓存端模式(Cache-Aside Pattern)是一种常用的缓存策略,它可以帮助我们按需加载数据到缓存中。当缓存失效时,应用会从数据存储中加载最新的数据并更新缓存。本文将详细讲解如安在 .NET Core 中实现缓存端模式,利用 Redis 来提升应用性能。
1. 为什么利用缓存端模式?

缓存端模式是指应用程序在访问数据时,起首尝试从缓存中获取数据。如果缓存中没有数据(缓存未命中),则应用程序会从数据存储(如数据库)加载数据,并将其存储到缓存中。缓存的生命周期由应用程序控制,而不是缓存系统主动决定。
与其他缓存策略(如直读和直写策略)差别,缓存端模式的优点在于:

  • 按需加载:只有在需要时才将数据加载到缓存中,克制了缓存空间浪费。
  • 机动控制缓存生命周期:缓存的过期时间、更新策略等都由应用程序控制,确保数据的时效性。
  • 提高性能:频仍读取的数据会被缓存起来,淘汰数据库的访问压力。
2. 实现步调

2.1 安装 Redis 客户端库

在 .NET Core 项目中利用 Redis,我们需要安装 StackExchange.Redis 包,这是一个性能优良且易于利用的 Redis 客户端库。你可以通过以下命令安装:
  1. dotnet add package StackExchange.Redis
复制代码
2.2 配置 Redis 连接字符串

在 appsettings.json 中配置 Redis 连接信息。假设你利用的是本地的 Redis 实例或 Azure Redis 缓存,连接字符串配置如下:
  1. {
  2.   "ConnectionStrings": {
  3.     "RedisConnection": "localhost:6379" // 连接本地 Redis 实例
  4.   }
  5. }
复制代码
这里,"RedisConnection" 是用于连接 Redis 的连接字符串。
2.3 创建 Redis 服务类

接下来,我们创建一个 RedisCacheService 类,用于管理与 Redis 的连接。为了提高性能,我们将连接利用 Lazy 实现懒加载,确保连接只会在第一次利用时初始化。
  1. using StackExchange.Redis;
  2. using Microsoft.Extensions.Configuration;
  3. public class RedisCacheService
  4. {
  5.     private static Lazy<ConnectionMultiplexer> _lazyConnection;
  6.     private static ConnectionMultiplexer _connection;
  7.     public RedisCacheService(IConfiguration configuration)
  8.     {
  9.         // 获取 Redis 连接字符串
  10.         string redisConnectionString = configuration.GetConnectionString("RedisConnection");
  11.         // 使用 Lazy 确保 Redis 连接只有一个实例,并且是懒加载的
  12.         _lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
  13.             ConnectionMultiplexer.Connect(redisConnectionString));
  14.     }
  15.     // 获取 Redis 数据库实例
  16.     public IDatabase GetDatabase()
  17.     {
  18.         return _lazyConnection.Value.GetDatabase();
  19.     }
  20.     // 获取 Redis 连接实例
  21.     public ConnectionMultiplexer GetConnection()
  22.     {
  23.         return _lazyConnection.Value;
  24.     }
  25. }
复制代码
此类将 Redis 连接字符串作为参数,并提供一个 GetDatabase 方法来获取 Redis 数据库实例,供后续的缓存操纵利用。
2.4 在 Startup.cs 中注册 Redis 服务

为了在整个应用中共享 Redis 服务,我们需要将 RedisCacheService 注册为单例服务。在 Startup.cs 文件的 ConfigureServices 方法中注册服务:
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3.     services.AddSingleton<RedisCacheService>();  // 注册 RedisCacheService 为单例服务
  4. }
复制代码
2.5 实现缓存端模式

现在,我们可以实现缓存端模式。在缓存端模式中,当应用程序需要数据时,起首检查缓存是否包含该数据。如果缓存中没有数据(缓存未命中),则从数据存储(如数据库)中加载数据,并将其存入缓存中。我们还要为缓存设置过期时间,确保数据的时效性。
以下是实现缓存端模式的代码示例:
  1. using Newtonsoft.Json;
  2. using StackExchange.Redis;
  3. using System;
  4. using System.Threading.Tasks;
  5. public class MyEntity
  6. {
  7.     public int Id { get; set; }
  8.     public string Name { get; set; }
  9. }
  10. public class MyEntityService
  11. {
  12.     private readonly RedisCacheService _redisCacheService;
  13.     private readonly TimeSpan _cacheExpiration = TimeSpan.FromMinutes(5);
  14.     public MyEntityService(RedisCacheService redisCacheService)
  15.     {
  16.         _redisCacheService = redisCacheService;
  17.     }
  18.     // 获取实体的异步方法
  19.     public async Task<MyEntity> GetMyEntityAsync(int id)
  20.     {
  21.         var cache = _redisCacheService.GetDatabase();
  22.         var key = $"MyEntity:{id}";  // 用 id 生成唯一的缓存键
  23.         // 尝试从缓存中获取数据
  24.         var cachedData = await cache.StringGetAsync(key);
  25.         if (!string.IsNullOrEmpty(cachedData))
  26.         {
  27.             // 如果缓存中有数据,直接返回缓存的值
  28.             return JsonConvert.DeserializeObject<MyEntity>(cachedData);
  29.         }
  30.         // 如果缓存没有数据,执行数据库查询(此处假设从数据库获取数据)
  31.         MyEntity entityFromDb = await GetEntityFromDbAsync(id);
  32.         // 如果数据库中找到了该数据,缓存并返回
  33.         if (entityFromDb != null)
  34.         {
  35.             // 将从数据库获取的数据存入缓存
  36.             await cache.StringSetAsync(key, JsonConvert.SerializeObject(entityFromDb), _cacheExpiration);
  37.         }
  38.         return entityFromDb;
  39.     }
  40.     // 假设此方法是从数据库中获取数据
  41.     private Task<MyEntity> GetEntityFromDbAsync(int id)
  42.     {
  43.         // 模拟从数据库查询数据
  44.         return Task.FromResult(new MyEntity { Id = id, Name = "Entity " + id });
  45.     }
  46. }
复制代码
解释:


  • 缓存加载:在 GetMyEntityAsync 方法中,起首利用 StringGetAsync 尝试从 Redis 缓存中读取数据。如果缓存中有数据,直接返回缓存的内容。
  • 缓存失效:如果缓存未命中,方法会从数据库加载数据,并将其存入 Redis 缓存中,设置缓存的过期时间为 5 分钟。
  • 缓存更新:在缓存更新时,应用程序会先从数据库加载数据,然后缓存该数据。如果缓存中已存在数据,旧的缓存将被新的数据覆盖。
2.6 使缓存数据失效

当应用程序更新数据库中的数据时,需要从缓存中删除该数据,克制缓存中存留过时的数据。下面是一个更新实体并使缓存失效的例子:
  1. public async Task UpdateEntityAsync(MyEntity entity)
  2. {
  3.     // 更新数据库中的实体
  4.     await UpdateEntityInDbAsync(entity);
  5.     // 从缓存中删除该实体
  6.     var cache = _redisCacheService.GetDatabase();
  7.     var key = $"MyEntity:{entity.Id}";
  8.     await cache.KeyDeleteAsync(key);  // 删除缓存中的条目
  9. }
  10. private Task UpdateEntityInDbAsync(MyEntity entity)
  11. {
  12.     // 模拟更新数据库中的数据
  13.     return Task.CompletedTask;
  14. }
复制代码
在更新数据库之后,我们从 Redis 缓存中删除该实体的缓存条目,确保下次从数据库加载时数据是最新的。
3. 性能与优化

在实现缓存端模式时,有一些细节需要特殊留意:

  • 缓存过期时间:公道设置缓存过期时间非常紧张。如果缓存过期时间太短,应用程序会频仍地从数据库加载数据,浪费性能;如果过期时间太长,缓存中的数据可能会过时。建议根据数据的访问频率和变化频率来调解过期时间。
  • 缓存淘汰策略:Redis 提供了多种缓存淘汰策略(如 LRU - 近来最少利用)。根据实际需求,可以配置 Redis 利用合适的淘汰策略,以确保缓存空间的有效利用。
4. 总结

通过实现缓存端模式,我们能够高效地将缓存与数据存储结合,优化应用性能。在 .NET Core 中,结合利用 Redis 和 StackExchange.Redis 库,我们可以按需加载数据到缓存中,并确保缓存的数据与数据存储中的数据保持同等。缓存端模式非常得当于读取频仍的数据,可以大幅淘汰数据库访问,提高系统的相应速率和可靠性。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表