Bài viết này thảo luận những kiến thức cơ bản về Azure Redis Cache và cách triển khai chúng bằng .NET Core Web API.
Chương trình làm việc
- Giới thiệu
- Bộ nhớ đệm là gì?
- Các loại bộ đệm
- Redis Cache
- Thiết lập bộ đệm ẩn Azure Redis
- Thực hiện từng bước
Điều kiện tiên quyết
- Visual Studio 2022
- Tài khoản Azure
- .NET Core 6
Giới thiệu
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 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.
Bộ đệ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 vào bộ lưu trữ tạm thời, nó sẽ cải thiện hiệu suất một cách đáng kể và tránh các 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.


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à sử dụng 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à nó giống nhau đối với tất cả người dùng. Khi chúng tôi không sử dụng bộ đệm, mỗi bộ đệm sẽ truy cập cơ sở dữ liệu không cần thiết để tìm nạp dữ liệu. Ở phía bên kia. bạn có thể thấy chúng tôi sử dụng bộ đệm và trong trường hợp đó, 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 sẽ truy cập cơ sở dữ liệu và tìm nạp dữ liệu và lưu trữ vào bộ nhớ đệm, sau đó hai người dùng khác đã sử dụng dữ liệu đó từ bộ đệm mà không cần nhấn 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ộ nhớ đệm hỗ trợ .NET Core
- Bộ nhớ đệm trong bộ nhớ
- Bộ nhớ đệm được phân phối
Khi chúng tôi sử dụng Bộ nhớ đệm trong bộ nhớ, dữ liệu sẽ được lưu trữ trong bộ nhớ máy chủ ứng dụng; bất cứ khi nào chúng tôi cần, chúng tôi lấy dữ liệu từ đó và sử dụng nó ở 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

- Về cơ bản, trong bộ nhớ đệm phân tán, dữ liệu đượ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 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ó.
Redis Cache
- 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.
Thiết lập bộ nhớ đệm Azure Redis
Bước 1
Đăng nhập vào cổng Azure.
Bước 2
Tìm kiếm Azure Cache cho Redis trên thị trường và mở nó.

Bước 3
Nhấp vào tạo và cung cấp các thông tin khác.




Bước 4
Sau đó, hãy chuyển đến phần Khóa truy cập bên trong bộ đệm mà chúng tôi đã tạo trước đó và sao chép chuỗi kết nối chính mà chúng tôi cần bên trong API .NET Core Web.

Thực hiện từng bước
Bước 1
Mở studio trực quan và tạo dự án API .NET Core Web mới.

Bước 2
Định cấu hình dự án mới.
Bước 3
Cung cấp thêm chi tiết.
Bước 4
Cấu trúc dự án.
Bước 5
Tạo lớp chi tiết sản phẩm.
namespace AzureRedisCacheDemo.Models {
public class ProductDetails {
public int Id {
get;
set;
}
public string ProductName {
get;
set;
}
public string ProductDescription {
get;
set;
}
public int ProductPrice {
get;
set;
}
public int ProductStock {
get;
set;
}
}
} Bước 6
Tiếp theo, thêm Lớp ngữ cảnh Db bên trong thư mục Dữ liệu.
using AzureRedisCacheDemo.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
namespace AzureRedisCacheDemo.Data {
public class DbContextClass: DbContext {
public DbContextClass(DbContextOptions < DbContextClass > options): base(options) {}
public DbSet < ProductDetails > Products {
get;
set;
}
}
} Bước 7
Sau đó, thêm lớp Seed Data mà chúng ta sử dụng để chèn một số dữ liệu ban đầu.
using AzureRedisCacheDemo.Models;
using Microsoft.EntityFrameworkCore;
namespace AzureRedisCacheDemo.Data
{
public class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var context = new DbContextClass(
serviceProvider.GetRequiredService<DbContextOptions<DbContextClass>>()))
{
if (context.Products.Any())
{
return;
}
context.Products.AddRange(
new ProductDetails
{
Id = 1,
ProductName = "IPhone",
ProductDescription = "IPhone 14",
ProductPrice = 120000,
ProductStock = 100
},
new ProductDetails
{
Id = 2,
ProductName = "Samsung TV",
ProductDescription = "Smart TV",
ProductPrice = 400000,
ProductStock = 120
});
context.SaveChanges();
}
}
}
} Bước 8
Định cấu hình chuỗi kết nối Azure Redis Cache bên trong tệp appsinstall.json.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"RedisURL": "<valuefromportal>"
} Bước 9
Tạo lớp Trình quản lý cấu hình và Trình trợ giúp kết nối bên trong thư mục Trình trợ giúp mà chúng tôi sử dụng cho mục đích kết nối.
Trình quản lý cấu hình
namespace AzureRedisCacheDemo.Helper {
static class ConfigurationManager {
public static IConfiguration AppSetting {
get;
}
static ConfigurationManager() {
AppSetting = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build();
}
}
} Trình trợ giúp kết nối
using StackExchange.Redis;
namespace AzureRedisCacheDemo.Helper {
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 10
Tiếp theo, thêm IProductService bên trong Kho lưu trữ.
using AzureRedisCacheDemo.Models;
namespace AzureRedisCacheDemo.Repositories {
public interface IProductService {
public Task < List < ProductDetails >> ProductListAsync();
public Task < ProductDetails > GetProductDetailByIdAsync(int productId);
public Task < bool > AddProductAsync(ProductDetails productDetails);
public Task < bool > UpdateProductAsync(ProductDetails productDetails);
public Task < bool > DeleteProductAsync(int productId);
}
} Bước 11
Tiếp theo, tạo lớp ProductService và triển khai giao diện IProductService bên trong đó.
using AzureRedisCacheDemo.Data;
using AzureRedisCacheDemo.Models;
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace AzureRedisCacheDemo.Repositories {
public class ProductService: IProductService {
private readonly DbContextClass dbContextClass;
public ProductService(DbContextClass dbContextClass) {
this.dbContextClass = dbContextClass;
}
public async Task < List < ProductDetails >> ProductListAsync() {
return await dbContextClass.Products.ToListAsync();
}
public async Task < ProductDetails > GetProductDetailByIdAsync(int productId) {
return await dbContextClass.Products.Where(ele => ele.Id == productId).FirstOrDefaultAsync();
}
public async Task < bool > AddProductAsync(ProductDetails productDetails) {
await dbContextClass.Products.AddAsync(productDetails);
var result = await dbContextClass.SaveChangesAsync();
if (result > 0) {
return true;
} else {
return false;
}
}
public async Task < bool > UpdateProductAsync(ProductDetails productDetails) {
var isProduct = ProductDetailsExists(productDetails.Id);
if (isProduct) {
dbContextClass.Products.Update(productDetails);
var result = await dbContextClass.SaveChangesAsync();
if (result > 0) {
return true;
} else {
return false;
}
}
return false;
}
public async Task < bool > DeleteProductAsync(int productId) {
var findProductData = dbContextClass.Products.Where(_ => _.Id == productId).FirstOrDefault();
if (findProductData != null) {
dbContextClass.Products.Remove(findProductData);
var result = await dbContextClass.SaveChangesAsync();
if (result > 0) {
return true;
} else {
return false;
}
}
return false;
}
private bool ProductDetailsExists(int productId) {
return dbContextClass.Products.Any(e => e.Id == productId);
}
}
} Bước 12
Tạo giao diện IRedisCache.
namespace AzureRedisCacheDemo.Repositories.AzureRedisCache {
public interface IRedisCache {
T GetCacheData < T > (string key);
bool SetCacheData < T > (string key, T value, DateTimeOffset expirationTime);
object RemoveData(string key);
}
} Bước 13
Sau đó, tạo một lớp RedisCache và triển khai phương thức giao diện bên trong lớp mà chúng ta đã tạo trước đó.
using AzureRedisCacheDemo.Helper;
using Newtonsoft.Json;
using StackExchange.Redis;
namespace AzureRedisCacheDemo.Repositories.AzureRedisCache
{
public class RedisCache : IRedisCache
{
private IDatabase _db;
public RedisCache()
{
ConfigureRedis();
}
private void ConfigureRedis()
{
_db = ConnectionHelper.Connection.GetDatabase();
}
public T GetCacheData<T>(string key)
{
var value = _db.StringGet(key);
if (!string.IsNullOrEmpty(value))
{
return JsonConvert.DeserializeObject<T>(value);
}
return default;
}
public object RemoveData(string key)
{
bool _isKeyExist = _db.KeyExists(key);
if (_isKeyExist == true)
{
return _db.KeyDelete(key);
}
return false;
}
public bool SetCacheData<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;
}
}
} Bước 14
Tạo Bộ điều khiển sản phẩm mới.
using AzureRedisCacheDemo.Models;
using AzureRedisCacheDemo.Repositories;
using AzureRedisCacheDemo.Repositories.AzureRedisCache;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace AzureRedisCacheDemo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
private readonly IRedisCache _redisCache;
public ProductsController(IProductService productService, IRedisCache redisCache)
{
_productService = productService;
_redisCache = redisCache;
}
/// <summary>
/// Product List
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<ActionResult<List<ProductDetails>>> ProductListAsync()
{
var cacheData = _redisCache.GetCacheData<List<ProductDetails>>("product");
if (cacheData != null)
{
return new List<ProductDetails>(cacheData);
}
var productList = await _productService.ProductListAsync();
if(productList != null)
{
var expirationTime = DateTimeOffset.Now.AddMinutes(5.0);
_redisCache.SetCacheData<List<ProductDetails>>("product", productList, expirationTime);
return Ok(productList);
}
else
{
return NoContent();
}
}
/// <summary>
/// Get Product By Id
/// </summary>
/// <param name="productId"></param>
/// <returns></returns>
[HttpGet("{productId}")]
public async Task<ActionResult<ProductDetails>> GetProductDetailsByIdAsync(int productId)
{
var cacheData = _redisCache.GetCacheData<List<ProductDetails>>("product");
if (cacheData != null)
{
ProductDetails filteredData = cacheData.Where(x => x.Id == productId).FirstOrDefault();
return new ActionResult<ProductDetails>(filteredData);
}
var productDetails = await _productService.GetProductDetailByIdAsync(productId);
if(productDetails != null)
{
return Ok(productDetails);
}
else
{
return NotFound();
}
}
/// <summary>
/// Add a new product
/// </summary>
/// <param name="productDetails"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> AddProductAsync(ProductDetails productDetails)
{
var isProductInserted = await _productService.AddProductAsync(productDetails);
_redisCache.RemoveData("product");
if (isProductInserted)
{
return Ok(isProductInserted);
}
else
{
return BadRequest();
}
}
/// <summary>
/// Update product details
/// </summary>
/// <param name="productDetails"></param>
/// <returns></returns>
[HttpPut]
public async Task<IActionResult> UpdateProductAsync(ProductDetails productDetails)
{
var isProductUpdated = await _productService.UpdateProductAsync(productDetails);
_redisCache.RemoveData("product");
if (isProductUpdated)
{
return Ok(isProductUpdated);
}
else
{
return BadRequest();
}
}
/// <summary>
/// Delete product by id
/// </summary>
/// <param name="productId"></param>
/// <returns></returns>
[HttpDelete]
public async Task<IActionResult> DeleteProductAsync(int productId)
{
var isProductDeleted = await _productService.DeleteProductAsync(productId);
_redisCache.RemoveData("product");
if (isProductDeleted)
{
return Ok(isProductDeleted);
}
else
{
return BadRequest();
}
}
}
} Bước 15
Đăng ký một số dịch vụ bên trong lớp Chương trình.
using AzureRedisCacheDemo.Data;
using AzureRedisCacheDemo.Models;
using AzureRedisCacheDemo.Repositories;
using AzureRedisCacheDemo.Repositories.AzureRedisCache;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using System;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddScoped < IProductService, ProductService > ();
builder.Services.AddDbContext < DbContextClass > (o => o.UseInMemoryDatabase("RedisCacheDemo"));
builder.Services.AddScoped < IRedisCache, RedisCache > ();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
using(var scope = app.Services.CreateScope()) {
var services = scope.ServiceProvider;
var context = services.GetRequiredService < DbContextClass > ();
SeedData.Initialize(services);
}
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run(); Bước 16
Cuối cùng, hãy chạy ứng dụng và chúng ta có thể thấy giao diện người dùng vênh vang với các điểm cuối của API.
Bước 17
Nhấn vào điểm cuối lấy sản phẩm và mở Redis CLI bên trong Cổng thông tin Azure và ở đó bạn có thể thấy danh sách sản phẩm sẽ được lưu trữ khi chúng ta nhấn vào điểm cuối lần đầu tiên.
Trong trường hợp này, trước tiên, chúng tôi kiểm tra xem dữ liệu có trong bộ đệm hay không. Nếu không thì chúng tôi lấy dữ liệu từ cơ sở dữ liệu và lưu nó vào bộ đệm. Chúng tôi đã viết mã liên quan đến mã đó bên trong bộ điều khiển. Vì vậy, lần sau chúng ta lấy dữ liệu từ bộ đệm. Nếu bạn đặt một trình gỡ lỗi bên trong bộ điều khiển thì bạn có thể dễ dàng hiểu được mọi thứ sẽ hoạt động như thế nào.
URL GitHub
https://github.com/Jaydeep-007/AzureRedisCacheDemo/tree/master/AzureRedisCacheDemo
Kết luận
Ở đây chúng ta đã xem phần giới thiệu bộ đệm và cấu hình của chúng trên Azure. Ngoài ra, việc triển khai từng bước bằng .NET Core Web API.