Hybrid Cache (Hybrid Cache)
Hybrid Cache เป็น Unified Library สำหรับ Caching Data ใน In-memory และ External Sources ซึ่งอาจเรียกได้ว่า Multi-tier Caching กล่าวคือ Multi-tier Caching นี้เป็น Replacement สำหรับ IDistributedCache และ IMemoryCache มันยัง Intended (ตั้งใจ) ให้ Simplify การใช้ Caching ใน .NET วิธีเก่าสำหรับ Distributed Caching ต้องเขียน Code เพิ่มเพื่อ Ensure Things ถูก Cache และ Retrieve ได้ถูกต้อง Package นี้เป็น Amazing Addition สำหรับ Simplify Caching ใน .NET ทำให้เป็น Robust Caching Solution เราใช้ Microsoft.Extensions.Caching.Hybrid NuGet Package ในบทความนี้ เราจะครอบคลุม Features ทั้งหมดของ Hybrid Cache Package
Package Features
- Extensible Code: Code ที่เขียนสำหรับ In-memory Cache ใช้ As-is ได้โดยไม่ต้อง Modify สำหรับ Integration กับ External Caching Servers เช่น Redis, SQL Server, etc.
- Concurrency Management: เพื่อใช้ Hybrid Cache เราต้องใช้ HybridCache Class เป็น Dependency Service Class นี้ Ensure ว่า Only One Instance ใช้ Get Data สำหรับ Key ใดๆ และ No Concurrent Requests ทำสำหรับ Entry เดียวกัน All Concurrent Requests Wait สำหรับ Request นี้ให้ Complete
- Multi-source Caching/Primary-secondary Source Caching: ถ้า Application Configure Multiple Sources สำหรับ Caching Data จะ Stored ที่ทุก Location
เพื่อ Get Data จะ Check ใน Primary Source ก่อน ถ้า Data ไม่ Available Request จะ Forward ไป Secondary Source ตาม Diagram ด้านล่าง Scenario 1 ในสีน้ำเงิน และ Scenario 2 ในสีแดง
Code Setup
เพื่อเริ่มต้น เราจะ Install Microsoft.Extensions.Caching.Hybrid Package ก่อน
ใน Program.cs เราจะเขียน Code ด้านล่างเพื่อ Add Hybrid Cache
builder.Services.AddHybridCache();
เพื่อ Configure Hybrid Cache เราเขียน Code ด้านล่างใน AddHybridCache เป็น Setup Action ตัวอย่างด้านล่าง
builder.Services.AddHybridCache(options => {
options.ReportTagMetrics = true;
options.DefaultEntryOptions = new Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions {
Expiration = TimeSpan.FromSeconds(30),
LocalCacheExpiration = TimeSpan.FromSeconds(30),
};
});
Implement In-memory Cache
Dependency Service Configuration ด้านบนเพียงพอสำหรับ In-memory Caching ด้านล่างคือ Sample Code ใน API Controller สำหรับ Set และ Get Key และ Value ใน Application Memory
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Hybrid;
namespace HybridCacheDemoApplication.Controllers {
[ApiController]
[Route("[controller]")]
public class CacheController : ControllerBase {
private readonly HybridCache _cache;
const string cacheKey = "ping";
public CacheController(HybridCache cache) {
_cache = cache;
}
[HttpGet(Name = "GetPingKey")]
public async Task<IActionResult> Get() {
var keydata = await _cache.GetOrCreateAsync<string>(
cacheKey, // Unique key to the cache entry
async cancel => await Task.FromResult("pong from get")
);
return Ok(new {message = $"{cacheKey} data: {keydata}"});
}
[HttpGet("set",Name = "SetPingKey")]
public async Task<IActionResult> Set() {
await _cache.SetAsync<string>(cacheKey, "ping");
return Ok(new { message = $"{cacheKey} is set" });
}
}
}
เพื่อเข้าใจ Code นี้ทำงานอย่างไร ดู Table ด้านล่างตาม Sequence
Cache Execution Demo Table
| Sequence | Endpoint | Output | Explanation |
|---|---|---|---|
| 1 | https://localhost:5154/cache/ | { "message": "ping data: pong from get" } |
Endpoint นี้ Set Cache Value เป็น "pong from get" เมื่อ Value ไม่ Set จึง Print "pong from get" |
| 2 | https://localhost:5154/cache/set | { "message": "ping is set" } |
Endpoint นี้จะ Set Value ใน Cache |
| 3 | https://localhost:5154/cache/ | { "message": "ping data: ping" } |
Endpoint เดียวกับ Step 1 แตคราวนี้ Value มีใน Cache แล้ว |
Delete Cache Key: เพื่อ Remove Cache Keys เราใช้ Implementation ด้านล่าง
[HttpGet("del",Name="DeletePingKey")]
public async Task<IActionResult> RemoveKey() {
await _cache.RemoveAsync(cacheKey); //Removes data
return Ok(new {message=$"{cacheKey} removed"});
}
Distributed Caching ใช้ Redis Server
เพื่อ Implement Distributed Caching เราต้องทำ Additional Dependency Service Configurations สำหรับตัวอย่างนี้ เราจะใช้ Redis Cache เป็น External Caching Source
ตอนนี้ เราจะ Configure Redis Package ด้วย Microsoft.Extensions.Caching.StackExchangeRedis
ติดตั้งแล้ว เราต้อง Add Code ด้านล่างเพื่อ Add Redis Connection String จะอยู่ใน Format {HOST_NAME}:{PORT_NUMBER},password={PASSWORD}
builder.Services.AddStackExchangeRedisCache(options => {
options.Configuration = builder.Configuration.GetConnectionString("RedisConnectionString");
});
ตอนนี้ เราจะ Invoke https://localhost:5154/cache/set และ Data จะ Set ใน Redis Cache Seamlessly ด้านล่างคือลักษณะใน Redis

สังเกตว่า Code ของเราทำงาน Seamlessly เพียงแค่เพิ่ม Dependency สำหรับ Distributed Caching Server คือ Redis ใน Scenario ของเรา
Serialization
เพื่อส่ง Data ไป External Caching Server Package นี้ใช้ byte[], string, และ System.Text.Json นี้ Customizable เพิ่มเติมด้วย .AddSerializer() หรือ AddSerializerFactory() Methods เพิ่มเติมกับ AddHybrid Cache Dependency Service เมื่อเราใช้ Optimized Serializer มากขึ้น พวกมันปรับปรุง Performance ของ Application
More Customizations
เราสามารถ Customize Behavior ของ Cache Services เพิ่มเติมได้โดย Setting Flags เมื่อ Configure Dependencies ตัวอย่าง Flag หนึ่ง Disable Compression สำหรับ Caching
หมายเหตุ. นี่ไม่ใช่ Best Practice แต่อาจแตกต่างตาม Scenario เมื่อ Compression ไม่จำเป็นหรือไม่ใช้
builder.Services.AddHybridCache(options => {
options.ReportTagMetrics = true;
options.DefaultEntryOptions = new Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions {
Flags = Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableCompression
};
});
Experimental Feature: Tags - ทำงานกับ Inter-related Keys
บางครั้งเราอาจ Deal กับ Many Interrelated Keys ตัวอย่าง: ใน E-commerce Application เรา Cache หลาย Fields ที่ Correspond 到 Cart Item 到 User สำหรับนี้ เราสามารถสร้าง Tags ได้
Code ด้านล่าง สำหรับทำงานกับ Inter-related Keys เราสร้าง Tag ชื่อ "testdata" เราสามารถ Add มากกว่า 1 Tag ขึ้นอยู่กับ Type of Grouping ที่ Apply ได้สำหรับ Scenarios ต่างๆ Code นี้ Self-explanatory แต่ถ้ามี Confusion ให้ mention ใน Comments
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Hybrid;
namespace HybridCacheDemoApplication.Controllers {
[ApiController]
[Route("[controller]")]
public class CacheController : ControllerBase {
private readonly HybridCache _cache;
const string cacheKey = "ping";
public CacheController(HybridCache cache) {
_cache = cache;
}
[HttpGet(Name = "GetPingKey")]
public async Task<IActionResult> Get() {
var keydata = await _cache.GetOrCreateAsync<string>(
cacheKey, // Unique key to the cache entry
async cancel => await Task.FromResult("pong from get"),
tags: ["testdata"]
);
return Ok(new {message = $"{cacheKey} data: {keydata}"});
}
[HttpGet("set",Name = "SetPingKey")]
public async Task<IActionResult> Set() {
await _cache.SetAsync<string>(cacheKey, "ping", tags: ["testdata"] );
return Ok(new { message = $"{cacheKey} is set" });
}
[HttpGet("del",Name="DeletePingKey")]
public async Task<IActionResult> RemoveKey() {
await _cache.RemoveAsync(cacheKey);
return Ok(new {message=$"{cacheKey} removed"});
}
[HttpGet("delbytag", Name = "DeleteByTestTags")]
public async Task<IActionResult> RemoveKeyByTags() {
await _cache.RemoveByTagAsync(["testdata"]);
return Ok(new { message = $"{cacheKey} removed" });
}
}
}
ขอบคุณที่อ่านจนจบ Hybrid Caching นี้เสนอ Amazing Benefits และหวังว่าคุณจะพบว่ามัน Helpful