Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Redis

Tích hợp Redis Caching vào API .NET Core để tăng hiệu suất và khả năng mở rộng

Giới thiệu

Chúng ta sẽ thảo luận về Bộ nhớ đệm trong .NET Core và cách nó hoạt động. Vì vậy, chúng tôi xem xét từng vấn đề sau đây.

  • Giới thiệu về bộ nhớ đệm
  • Bộ đệm là gì
  • Các loại bộ đệm
  • Triển khai bộ đệm

Bộ nhớ đệm hiện nay rất phổ biến trong ngành công nghiệp phần mềm vì nó sẽ cải thiện hiệu suất và khả năng mở rộng của ứng dụng. Chúng tôi sử dụng nhiều ứng dụng web như Gmail và Facebook và xem mức độ phản hồi của chúng và chúng tôi có trải nghiệm người dùng tuyệt vời. Có rất nhiều người dùng sử dụng Internet và nếu một ứng dụng có nhu cầu và lưu lượng truy cập mạng lớn,  chúng tôi cần quan tâm đến nhiều thứ giúp chúng tôi cải thiện hiệu suất và khả năng phản hồi của ứng dụng. Vì vậy, nhờ đó mà có giải pháp về bộ nhớ đệm và đó là lý do tại sao bộ nhớ đệm lại xuất hiện.

Vì vậy, hãy bắt đầu từng cái một.

Bộ nhớ đệm là gì?

Bộ đệm là bộ nhớ lưu trữ được sử dụng để lưu trữ dữ liệu truy cập thường xuyên trong bộ lưu trữ tạm thời, nó sẽ cải thiện hiệu suất một cách đáng kể, tránh các lần truy cập cơ sở dữ liệu không cần thiết và lưu trữ dữ liệu được sử dụng thường xuyên vào bộ đệm bất cứ khi nào chúng ta cần.

Tích hợp Redis Caching vào API .NET Core để tăng hiệu suất và khả năng mở rộng

Tích hợp Redis Caching vào API .NET Core để tăng hiệu suất và khả năng mở rộng

Như bạn thấy trong hình trên, có hai trường hợp, một là không sử dụng bộ đệm và một là có bộ đệm. Vì vậy, ở đây, khi chúng ta không sử dụng bộ đệm, trong trường hợp đó, giả sử người dùng muốn có dữ liệu, thì họ sẽ truy cập cơ sở dữ liệu mỗi lần và điều đó sẽ làm tăng độ phức tạp về thời gian và giảm hiệu suất trong trường hợp có một số dữ liệu tĩnh mà người dùng muốn và tất cả người dùng đều giống nhau. Trong trường hợp đó, khi chúng ta không sử dụng bộ nhớ đệm thì mỗi bộ đệm sẽ truy cập vào cơ sở dữ liệu không cần thiết để tìm nạp dữ liệu. Mặt khác, như bạn có thể thấy, chúng tôi sử dụng bộ đệm và trong trường hợp đó, nếu có cùng một dữ liệu tĩnh và giống nhau cho tất cả người dùng thì chỉ người dùng đầu tiên mới truy cập cơ sở dữ liệu, tìm nạp dữ liệu và lưu trữ nó vào bộ nhớ đệm và sau đó hai người dùng khác sử dụng dữ liệu đó từ bộ đệm mà không cần truy cập cơ sở dữ liệu để tìm nạp dữ liệu một cách không cần thiết.

Các loại bộ đệm

Về cơ bản, có hai loại bộ đệm mà .NET Core hỗ trợ.

  1. Bộ nhớ đệm trong bộ nhớ
  2. Bộ nhớ đệm được phân phối

Khi chúng tôi sử dụng Bộ nhớ đệm trong bộ nhớ thì trong trường hợp đó, dữ liệu sẽ được lưu trữ trong bộ nhớ máy chủ ứng dụng và bất cứ khi nào chúng tôi cần, chúng tôi sẽ tìm nạp dữ liệu từ đó và sử dụng ở bất cứ nơi nào chúng tôi cần. Và trong Distributed Caching, có nhiều cơ chế của bên thứ ba như Redis và nhiều cơ chế khác. Nhưng trong phần này, chúng ta sẽ tìm hiểu chi tiết về Redis Cache và cách nó hoạt động trong .NET Core

Bộ nhớ đệm được phân phối

Tích hợp Redis Caching vào API .NET Core để tăng hiệu suất và khả năng mở rộng

  • Về cơ bản, trong bộ nhớ đệm phân tán, dữ liệu g được lưu trữ và chia sẻ giữa nhiều máy chủ
  • Ngoài ra, thật dễ dàng để cải thiện khả năng mở rộng và hiệu suất của ứng dụng sau khi quản lý tải giữa nhiều máy chủ khi chúng tôi sử dụng ứng dụng có nhiều bên thuê
  • Giả sử, trong tương lai, nếu một máy chủ gặp sự cố và khởi động lại thì ứng dụng sẽ không có bất kỳ tác động nào vì nhiều máy chủ đáp ứng nhu cầu của chúng ta nếu chúng ta muốn

Redis là bộ đệm phổ biến nhất, được nhiều công ty sử dụng hiện nay để cải thiện hiệu suất và khả năng mở rộng của ứng dụng. Vì vậy, chúng ta sẽ thảo luận từng cái một về Redis và cách sử dụng nó.

Bộ nhớ đệm Redis

  • Redis là kho lưu trữ Cấu trúc dữ liệu trong bộ nhớ Nguồn mở (Được cấp phép BSD) được sử dụng làm cơ sở dữ liệu.
  • Về cơ bản, nó được sử dụng để lưu trữ một số dữ liệu tĩnh và được sử dụng thường xuyên bên trong bộ nhớ đệm, đồng thời sử dụng và dự trữ dữ liệu đó theo yêu cầu của người dùng.
  • Có nhiều cấu trúc dữ liệu có trong Redis mà chúng ta có thể sử dụng như Danh sách, Bộ, Băm, Luồng và nhiều cấu trúc khác để lưu trữ dữ liệu.

Cài đặt Redis Cache

Bước 1. Tải xuống Máy chủ Redis bằng URL sau.

https://github.com/microsoftarchive/redis/releases/tag/win-3.0.504

Bước 2. Giải nén tệp zip rồi mở Redis Server và Redis CLI.

Tích hợp Redis Caching vào API .NET Core để tăng hiệu suất và khả năng mở rộng

Triển khai Redis Cache bằng .NET Core API

Bước 1. Tạo ứng dụng web .NET Core API

Bước 2. Cài đặt các Gói NuGet sau, cần thực hiện từng bước trong ứng dụng của chúng tôi

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Swashbuckle.AspNetCore
  • StackExchange.Redis

Bước 3. Tạo thư mục Model và tạo một Lớp Sản phẩm bên trong đó với các chi tiết.

namespace RedisCacheDemo.Model
{
 public class Product
 {
 public int ProductId { get; set; }
 public string ProductName { get; set; }
 public string ProductDescription { get; set; }
 public int Stock { get; set; }
 }
}

Bước 4. Tiếp theo, Tạo Lớp DbContextClass cho các hoạt động của Cơ sở dữ liệu, như tôi đã trình bày bên dưới.

using Microsoft.EntityFrameworkCore;
using RedisCacheDemo.Model;
namespace RedisCacheDemo.Data {
 public class DbContextClass: DbContext {
 public DbContextClass(DbContextOptions < DbContextClass > options): base(options) {}
 public DbSet < Product > Products {
 get;
 set;
 }
 }
}

Bước 5. Bây giờ, chúng ta sẽ tạo Giao diện ICacheService và Lớp CacheService để sử dụng liên quan đến Redis Cache.

using System;
namespace RedisCacheDemo.Cache
{
 public interface ICacheService
 {
 /// <summary>
 /// Get Data using key
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="key"></param>
 /// <returns></returns>
 T GetData<T>(string key);
 /// <summary> 
 /// Set Data with Value and Expiration Time of Key
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="key"></param>
 /// <param name="value"></param>
 /// <param name="expirationTime"></param>
 /// <returns></returns>
 bool SetData<T>(string key, T value, DateTimeOffset expirationTime);
 /// <summary>
 /// Remove Data 
 /// </summary>
 /// <param name="key"></param>
 /// <returns></returns>
 object RemoveData(string key);
 }
}
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
namespace RedisCacheDemo.Cache {
 public class CacheService: ICacheService {
 private IDatabase _db;
 public CacheService() {
 ConfigureRedis();
 }
 private void ConfigureRedis() {
 _db = ConnectionHelper.Connection.GetDatabase();
 }
 public T GetData < T > (string key) {
 var value = _db.StringGet(key);
 if (!string.IsNullOrEmpty(value)) {
 return JsonConvert.DeserializeObject < T > (value);
 }
 return default;
 }
 public bool SetData < T > (string key, T value, DateTimeOffset expirationTime) {
 TimeSpan expiryTime = expirationTime.DateTime.Subtract(DateTime.Now);
 var isSet = _db.StringSet(key, JsonConvert.SerializeObject(value), expiryTime);
 return isSet;
 }
 public object RemoveData(string key) {
 bool _isKeyExist = _db.KeyExists(key);
 if (_isKeyExist == true) {
 return _db.KeyDelete(key);
 }
 return false;
 }
 }
}

Bước 6. Tạo lớp ProductController và tạo phương thức sau như hiển thị bên dưới.

using Microsoft.AspNetCore.Mvc;
using RedisCacheDemo.Cache;
using RedisCacheDemo.Data;
using RedisCacheDemo.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace RedisCacheDemo.Controllers {
 [Route("api/[controller]")]
 [ApiController]
 public class ProductController: ControllerBase {
 private readonly DbContextClass _dbContext;
 private readonly ICacheService _cacheService;
 public ProductController(DbContextClass dbContext, ICacheService cacheService) {
 _dbContext = dbContext;
 _cacheService = cacheService;
 }
 [HttpGet("products")]
 public IEnumerable < Product > Get() {
 var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product");
 if (cacheData != null) {
 return cacheData;
 }
 var expirationTime = DateTimeOffset.Now.AddMinutes(5.0);
 cacheData = _dbContext.Products.ToList();
 _cacheService.SetData < IEnumerable < Product >> ("product", cacheData, expirationTime);
 return cacheData;
 }
 [HttpGet("product")]
 public Product Get(int id) {
 Product filteredData;
 var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product");
 if (cacheData != null) {
 filteredData = cacheData.Where(x => x.ProductId == id).FirstOrDefault();
 return filteredData;
 }
 filteredData = _dbContext.Products.Where(x => x.ProductId == id).FirstOrDefault();
 return filteredData;
 }
 [HttpPost("addproduct")]
 public async Task < Product > Post(Product value) {
 var obj = await _dbContext.Products.AddAsync(value);
 _cacheService.RemoveData("product");
 _dbContext.SaveChanges();
 return obj.Entity;
 }
 [HttpPut("updateproduct")]
 public void Put(Product product) {
 _dbContext.Products.Update(product);
 _cacheService.RemoveData("product");
 _dbContext.SaveChanges();
 }
 [HttpDelete("deleteproduct")]
 public void Delete(int Id) {
 var filteredData = _dbContext.Products.Where(x => x.ProductId == Id).FirstOrDefault();
 _dbContext.Remove(filteredData);
 _cacheService.RemoveData("product");
 _dbContext.SaveChanges();
 }
 }
}

Bước 7. Thêm chuỗi kết nối SQL Server và URL Redis bên trong appsinstall.json.

{
 "Logging": {
 "LogLevel": {
 "Default": "Information",
 "Microsoft": "Warning",
 "Microsoft.Hosting.Lifetime": "Information"
 }
 },
 "AllowedHosts": "*",
 "RedisURL": "127.0.0.1:6379",
 "ConnectionStrings": {
 "DefaultConnection": "Data Source=Server;Initial Catalog=RedisCache;User Id=sa;Password=***;"
 }
}

Bước 8. Tiếp theo, hãy đăng ký ICacheService bên trong phương thức Dịch vụ định cấu hình của Lớp khởi động và cũng thêm một số cấu hình liên quan đến Swagger để kiểm tra các điểm cuối API của chúng tôi.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using RedisCacheDemo.Cache;
using RedisCacheDemo.Data;
namespace RedisCacheDemo {
 public class Startup {
 public Startup(IConfiguration configuration) {
 Configuration = configuration;
 }
 public IConfiguration Configuration {
 get;
 }
 // This method gets called by the runtime. Use this method to add services to the container.
 public void ConfigureServices(IServiceCollection services) {
 services.AddControllers();
 services.AddScoped < ICacheService, CacheService > ();
 services.AddDbContext < DbContextClass > (options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
 services.AddSwaggerGen(c => {
 c.SwaggerDoc("v1", new OpenApiInfo {
 Title = "RedisCacheDemo", Version = "v1"
 });
 });
 }
 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
 if (env.IsDevelopment()) {
 app.UseDeveloperExceptionPage();
 app.UseSwagger();
 app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "RedisCacheDemo v1"));
 }
 app.UseHttpsRedirection();
 app.UseRouting();
 app.UseAuthorization();
 app.UseEndpoints(endpoints => {
 endpoints.MapControllers();
 });
 }
 }
}

Bước 9. Tạo một Lớp ConfigurationManger để định cấu hình cài đặt ứng dụng ở đó

using Microsoft.Extensions.Configuration;
using System.IO;
namespace RedisCacheDemo {
 static class ConfigurationManager {
 public static IConfiguration AppSetting {
 get;
 }
 static ConfigurationManager() {
 AppSetting = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
 }
 }
}

Bước 10. Tiếp theo, Tạo Lớp trình trợ giúp kết nối cho kết nối Redis.

using StackExchange.Redis;
using System;
namespace RedisCacheDemo.Cache {
 public class ConnectionHelper {
 static ConnectionHelper() {
 ConnectionHelper.lazyConnection = new Lazy < ConnectionMultiplexer > (() => {
 return ConnectionMultiplexer.Connect(ConfigurationManager.AppSetting["RedisURL"]);
 });
 }
 private static Lazy < ConnectionMultiplexer > lazyConnection;
 public static ConnectionMultiplexer Connection {
 get {
 return lazyConnection.Value;
 }
 }
 }
}

Bước 11. Thực hiện di chuyển và cập nhật cơ sở dữ liệu để tạo cơ sở dữ liệu bằng cách sử dụng các lệnh sau trong Bảng điều khiển quản lý gói.

add-migration “FirstMigration”
update-database

Vì vậy, khi bạn nhập và thực thi lệnh này, nó sẽ tạo ra một số thứ liên quan đến việc di chuyển và tạo cơ sở dữ liệu bên trong SQL Server khi bạn đặt bên trong Chuỗi kết nối trong appsetting.json

Bước 12. Cuối cùng, chạy ứng dụng và thêm dữ liệu bằng giao diện người dùng vênh, sau đó kiểm tra cách hoạt động của bộ nhớ đệm bên trong sản phẩm và điểm cuối của sản phẩm.

Về cơ bản, tôi đã thêm bộ đệm vào sản phẩm và điểm cuối của sản phẩm trong bộ điều khiển; như bạn thấy, khi người dùng muốn tìm nạp dữ liệu của tất cả các sản phẩm, thì trước tiên, nó sẽ kiểm tra xem dữ liệu có trong Redis Cache hay không và nếu nó có trong bộ đệm thì hãy trả lại dữ liệu đó cho người dùng và nếu dữ liệu không có trong bộ đệm thì nó sẽ tìm nạp dữ liệu từ cơ sở dữ liệu và đồng thời đặt dữ liệu đó vào bộ đệm. Vì vậy, lần sau người dùng sẽ chỉ lấy nó từ bộ đệm và tránh truy cập vào cơ sở dữ liệu một cách không cần thiết

Ngoài ra, khi người dùng muốn tìm nạp dữ liệu bằng ID sản phẩm, như bạn thấy trong bộ điều khiển ở điểm cuối thứ hai của sản phẩm, chúng tôi sẽ tìm nạp dữ liệu từ bộ nhớ đệm của tất cả các sản phẩm rồi lọc bằng ID sản phẩm. Nếu điều đó xuất hiện, chúng tôi sẽ trả lại cho người dùng từ bộ nhớ đệm; nếu không, chúng tôi tìm nạp từ cơ sở dữ liệu và trả lại cho người dùng sau khi áp dụng bộ lọc.

Như bạn thấy bên trong bản cập nhật, xóa và đăng các điểm cuối của Bộ điều khiển sản phẩm, chúng tôi sử dụng phương thức xóa để xóa dữ liệu khóa sản phẩm khỏi bộ đệm. Có nhiều tình huống và cách sử dụng bộ nhớ đệm mà bạn có thể sử dụng tùy theo nhu cầu và yêu cầu của mình. Tôi chỉ muốn giới thiệu những kiến thức cơ bản về Redis Cache và cách nó hoạt động bên trong .NET Core mà tôi đã trình bày ở đây.

Ngoài ra, có một tình huống bạn cần quan tâm khi sử dụng bộ nhớ đệm. Giả sử có hai người dùng đang sử dụng ứng dụng của bạn. Khi đó những tình huống sau sẽ xảy ra.

  • Khi người dùng đầu tiên gửi yêu cầu tìm nạp dữ liệu của tất cả các sản phẩm, yêu cầu đầu tiên sẽ đến và sau đó nó sẽ kiểm tra xem dữ liệu có trong bộ đệm hay không. Nếu dữ liệu có trong bộ đệm thì nó sẽ tìm nạp dữ liệu từ cơ sở dữ liệu và cũng đặt dữ liệu đó vào bộ đệm.
  • Trong khi đó, Người dùng thứ hai gửi yêu cầu lấy thông tin chi tiết về sản phẩm. Điều đã xảy ra là yêu cầu cũng truy cập vào cơ sở dữ liệu trước khi hoàn thành yêu cầu của người dùng đầu tiên và do đó, người dùng thứ hai cũng truy cập cơ sở dữ liệu để tìm nạp chi tiết sản phẩm.
  • Vì vậy, có một giải pháp cho vấn đề này là sử dụng Cơ chế khóa như dưới đây

Tạo đối tượng khóa riêng tư này ở đầu lớp.

private static object _lock = new object()

Tiếp theo, Sửa đổi phương thức Get như tôi trình bày bên dưới.

public IEnumerable < Product > Get() {
 var cacheData = _cacheService.GetData < IEnumerable < Product >> ("product");
 if (cacheData != null) {
 return cacheData;
 }
 lock(_lock) {
 var expirationTime = DateTimeOffset.Now.AddMinutes(5.0);
 cacheData = _dbContext.Products.ToList();
 _cacheService.SetData < IEnumerable < Product >> ("product", cacheData, expirationTime);
 }
 return cacheData;
}

Vì vậy, ở đây, như bạn thấy, trước tiên, chúng tôi kiểm tra xem dữ liệu có trong bộ nhớ đệm hay không. Nếu có dữ liệu thì trả lại dữ liệu đó. Tiếp theo, nếu giá trị không có trong bộ đệm Redis, thì chúng tôi áp dụng khóa ở đó, sau đó yêu cầu sẽ bị khóa và nhập vào phần tìm nạp chi tiết sản phẩm từ cơ sở dữ liệu, sau đó cũng đặt nó vào bộ đệm và trả về dữ liệu. Vậy điều gì sẽ xảy ra khi người dùng thứ hai gửi yêu cầu trước khi yêu cầu của người dùng hoàn tất? Vì vậy, trong trường hợp đó, yêu cầu thứ hai nằm trong hàng đợi và sau khi hoàn thành yêu cầu đầu tiên của người dùng, yêu cầu thứ hai sẽ xuất hiện

Ngoài ra, bạn có thể xem các chi tiết chính đã có trong Redis bằng Redis CLI, như hiển thị bên dưới

Tích hợp Redis Caching vào API .NET Core để tăng hiệu suất và khả năng mở rộng

Vì vậy, ở đây bạn có thể thấy có nhiều lệnh cung cấp cho chúng tôi thông tin về các khóa có trong Redis Cache.

Đây là tất cả về Redis Cache trong .NET Core. Tôi hy vọng bạn hiểu những điều liên quan đến điều đó.

Chúc bạn viết mã vui vẻ!