ASP.NET Core 中的缓存机制

作者 : 慕源网 本文共5378个字,预计阅读时间需要14分钟 发布时间: 2021-09-24 共493人阅读

缓存是指存储常用数据的过程,以便可以更快地为将来的任何请求提供这些数据。因此,我们将最常用的数据复制到临时存储中,以便在将来来自客户端的调用中可以更快地访问它。如果我们试着用一个简单的例子来解释,让 User-1 请求一些数据,服务器需要 12-15 秒来获取数据。在获取时,我们会将获取的数据并行复制到任何临时存储中。所以现在,当 User-2 请求相同的数据时,这次我们将简单地从缓存中提供他的数据,并且响应只需要 1-2 秒,因为我们已经将响应存储在我们的缓存中。

有两个与缓存一起使用的重要术语,缓存命中缓存未命中。当可以在缓存中找到数据时发生缓存命中,当在缓存中找不到数据时发生缓存未命中。

缓存显着提高了应用程序的性能,降低了生成内容的复杂性。将应用程序设计为从不直接依赖于缓存内存是很重要的。应用程序应该只缓存不经常更改的数据,并且只有在缓存数据可用时才使用缓存数据。

ASP.NET Core 具有许多缓存功能。但其中的两种主要类型是,

  • 内存缓存
  • 分布式缓存

内存缓存

一个内存高速缓存存储在托管应用程序的单一服务器的内存。基本上,数据缓存在应用程序中。这是显着提高应用程序性能的最简单方法。

内存缓存的主要优点是它比分布式缓存快得多,因为它避免了通过网络进行通信,并且适用于小型应用程序。主要缺点是在云中部署时保持缓存的一致性。

使用 ASP.NET Core 实现内存缓存

首先创建一个 ASP.NET Core Web API 应用程序。

ASP.NET Core 中的缓存机制

现在在 Startup.cs 文件中添加以下行。这将为我们的应用程序添加一个非分布式内存缓存实现。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    //Rest of the code
}

现在让我们创建一个新的控制器“EmployeeController”。在这个控制器中,我们将实现我们的缓存。

[Route("api/[controller]")]
[ApiController]
public class EmployeeController : ControllerBase
{
    private readonly IMemoryCache _memoryCache;
    private readonly ApplicationContext _context;
    public EmployeeController(IMemoryCache memoryCache, ApplicationContext context)
    {
        _memoryCache = memoryCache;
        _context = context;
    }

    [HttpGet]
    public async Task<IActionResult> GetAllEmployee()
    {
        var cacheKey = "employeeList";
        //checks if cache entries exists
        if(!_memoryCache.TryGetValue(cacheKey, out List<Employee> employeeList))
        {
            //calling the server
            employeeList = await _context.Employees.ToListAsync();

            //setting up cache options
            var cacheExpiryOptions = new MemoryCacheEntryOptions
            {
                AbsoluteExpiration = DateTime.Now.AddSeconds(50),
                Priority = CacheItemPriority.High,
                SlidingExpiration = TimeSpan.FromSeconds(20)
            };
            //setting cache entries
            _memoryCache.Set(cacheKey, employeeList, cacheExpiryOptions);
        }
        return Ok(employeeList);
    }
}

这是一个非常简单的实现。我们只是检查是否有任何缓存值可用于特定缓存键。如果存在,它将从缓存中提供数据,如果不存在,我们将调用我们的服务并将数据保存在缓存中。

解释

第 9 行:将 ImemoryCache 注入构造函数

第 16 行:创建缓存键。众所周知,数据将保存为键值对。

第 18 行:检查缓存值是否可用于特定键。

第 24 行:设置缓存。MemoryCacheEntryOptions用于定义缓存的关键属性。其中一些属性是:

1. Priority – Priority 定义了在缓存中保留缓存条目的优先级。默认值设置为正常。

2. Sliding Expiration –一个特定的时间跨度,如果没有人使用,缓存将在该时间段内到期。由于我们将滑动过期时间设置为 20 秒,因此这意味着在缓存进入后,如果 20 秒内没有客户端请求,缓存将过期。

3. Absolute Expiration –指缓存条目的实际过期时间,不考虑滑动过期时间。在我们的代码中,我们将绝对过期时间设置为 50 秒。所以这意味着缓存肯定会每 50 秒过期一次。

现在让我们观察在实现内存缓存后我们的应用程序的性能提升。

为此,运行应用程序并使用 Postman 向 Web API 发送获取请求。因此,我们第一次向 API 发送请求大约需要 2061 毫秒。

ASP.NET Core 中的缓存机制

因此,当我们第一次调用 API 时,它直接从数据库中获取数据,然后我们将数据并行存储到缓存中。

现在,如果我们这次为相同的数据请求相同的端点,则只需要 20 毫秒。

ASP.NET Core 中的缓存机制

所以这是一个非常惊人的改进。就我而言,数据集很小。如果有大量关于这种情况的数据,它将大大改善我们的服务。

分布式缓存

分布式缓存是一种可以由一个或多个应用程序共享的缓存,它作为一种所有服务器都可以访问的外部服务进行维护。所以分布式缓存是应用程序外部的。

分布式缓存的主要优点是数据在多个服务器中保持一致,因为服务器位于应用程序外部,任何应用程序的任何故障都不会影响缓存服务器。

在这里,我们将尝试使用 Redis 实现分布式缓存。

Redis是一种开源(BSD 许可)、内存中数据结构存储,用作数据库缓存和消息代理。它是非常快速的基于键值的数据库,甚至是 NoSQL 数据库。所以Redis是实现高可用缓存的绝佳选择。

在 Docker 中设置 Redis

第1步

从 docker hub 拉取 docker Redis 镜像。

docker pull redis

ASP.NET Core 中的缓存机制

第2步

通过将 Redis 端口映射到我们的本地系统端口来运行 Redis 镜像。

docker run --name myrediscache -p 5003:379 -d redis

ASP.NET Core 中的缓存机制

第 3 步

启动容器。

docker start myrediscache

ASP.NET Core 中的缓存机制

现在我们的 Redis 已经设置好了,让我们开始使用 ASP.NET Core 应用程序实现分布式缓存。

使用 ASP.NET Core 实现分布式缓存(Redis)

创建一个 ASP.NET Core Web API 项目并使用 Nuget 包管理器安装以下库。

ASP.NET Core 中的缓存机制

由于我们已经添加了所需的包,现在在Startup.cs文件中注册服务。

public void ConfigureServices(IServiceCollection services) {
    //Rest of the code
    services.AddStackExchangeRedisCache(options => {
        options.Configuration = Configuration.GetConnectionString("Redis");
        options.InstanceName = "localRedis_";
    });
}

在这里,我们设置了“options.InstanceName”,它只是作为我们在 redis 服务器上的键名的前缀。前任。如果我们在 redis 服务器中设置缓存名称employeelist,它将类似于localRedis_employeelist。

我们将在 appsettings.json 中提供 Redis 的配置相关设置。

{
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "Redis": "localhost:5003",
    "DefaultConnection": "Data Source=.;Initial Catalog=BuildingDataDB;Integrated Security=True"
  }
}

创建一个帮助器类“DistributedCacheExtensions”,我们将在其中从 Redis 缓存获取和设置值。

public static class DistributedCacheExtension {
    public static async Task SetRecordAsync < T > (this IDistributedCache cache, string recodeId, T data, TimeSpan ? absoluteExpireTime = null, TimeSpan ? slidingExpirationTime = null) {
        var options = new DistributedCacheEntryOptions();
        options.AbsoluteExpirationRelativeToNow = absoluteExpireTime ?? TimeSpan.FromSeconds(60);
        options.SlidingExpiration = slidingExpirationTime;
        var jsonData = JsonSerializer.Serialize(data);
        await cache.SetStringAsync(recodeId, jsonData, options);
    }
    public static async Task < T > GetRecordAsync < T > (this IDistributedCache cache, string recordId) {
        var jsonData = await cache.GetStringAsync(recordId);
        if (jsonData is null) {
            return default (T);
        }
        return JsonSerializer.Deserialize < T > (jsonData);
    }
}

这里的代码是不言自明的。在“ SetRecodeAsync ”方法中,我们将数据保存到Redis Cache。在这里,我们使用AbsoluteExpirationRelativeToNow SlidingExpiration(第 12 行和第 13 行)配置了 IDistributedCache 服务器,我们已经在内存缓存部分讨论了这些术语。

在“ GetRecordAsync ”中,我们根据某些 recodeKey 获取缓存值。

现在我们将创建一个名为“StudentController”的控制器,

public class StudentController: ControllerBase {
    private readonly ApplicationContext _context = null;
    private readonly IDistributedCache _cache;
    public StudentController(ApplicationContext context, IDistributedCache cache) {
            _context = context;
            _cache = cache;
        }
        [HttpGet]
    public async Task < ActionResult < List < Student >>> Get() {
        var cacheKey = "GET_ALL_STUDENTS";
        List < Student > students = new List < Student > ();
        var data = await _cache.GetRecordAsync < List < Student >> (cacheKey);
        if (data is null) {
            Thread.Sleep(10000);
            data = _context.Student.ToList();
            await _cache.SetRecordAsync(cacheKey, data);
        }
        return data;
    }
}

解释

第 5 行:在我们的构造函数中注入 IDistributeCache。

第 15 行:创建缓存键

第 18 行:尝试从 Redis 缓存服务器获取 。如果在缓存服务器上找到数据,它将为客户端提供缓存数据。

第 20 行:检查缓存数据是否可用。如果数据没有被缓存,那么它将从数据库或其他服务中获取数据。因此,为了模拟它,我们故意使用Thread.Sleep()方法设置了一些延迟。

所以这很简单。

现在让我们运行应用程序。

所以第一次,我们调用student控制器的Get方法加载数据需要12秒左右。对于第一次运行,它没有在缓存中找到数据,因此它会转到数据库并获取数据,并将获取的数据并行保存到 Redis 缓存服务器。

ASP.NET Core 中的缓存机制

但在第二次运行中,它会在 28 毫秒内获取数据。因为用户第二次请求同一个数据应用,发现数据已经缓存在Redis服务器中,所以将缓存的数据提供给用户。

ASP.NET Core 中的缓存机制

这是我们应用程序的超级优化,速度极快。

因此,我们的缓存介绍之旅到此结束。在这里,我尽量保持示例简单,并讨论了它的基本概念。希望你会发现它有帮助。

快乐编码!


慕源网 » ASP.NET Core 中的缓存机制

常见问题FAQ

程序仅供学习研究,请勿用于非法用途,不得违反国家法律,否则后果自负,一切法律责任与本站无关。
请仔细阅读以上条款再购买,拍下即代表同意条款并遵守约定,谢谢大家支持理解!

发表评论

开通VIP 享更多特权,建议使用QQ登录