如果說系統架構是多台的情況呢?例如:Load Balance,這時就適合用 分散式快取
。
簡單來說,分散式快取
就是統一將快取資料存在某個 儲存體
,當多台機器去查詢資料時,就會指向該 儲存體
來進行存取。
這邊選用 Redis 來當作分散式快取的 儲存體
。
在實作前
- 先將 Redis 架在
localhost:6379
(架設可參考),並將連線字串加入 appsettings.json - 將專案參考
Microsoft.Extensions.Caching.StackExchangeRedis
於 Program.cs 注入 IDistributedCache
如下:
// 取得 appsettings 中的 Redis 連線字串
var redisConStr = builder.Configuration.GetSection("RedisCache:ConnectionString").Value;
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = redisConStr;
});
在建構式傳入 IDistributedCache 實體
如下:
private readonly IDistributedCache _distributedCache;
public DistributedCacheController(IDistributedCache distributedCache)
{
_distributedCache = distributedCache;
}
取得快取資料
如下:
var userId = 123;
// 取得快取資料,不存在則返回 null
var source = await _distributedCache.GetAsync(userId.ToString());
if (source == null)
{
throw new KeyNotFoundException();
}
var info = JsonSerializer.Deserialize<UserInfo>(source);
更新快取資料
如下:
var userId = 123;
await _distributedCache.SetStringAsync(
userId.ToString(), JsonSerializer.Serialize(info));
刪除快取資料
如下:
var userId = 123;
await _distributedCache.RemoveAsync(userId.ToString());
取得或新增快取資料
因為個人習慣使用 MemoryCache
的 GetOrCreate,所以也刻了一個擴充方法:
有關快取機制 Absolute
、Sliding
於上一篇有介紹過了,讀者就根據使用情境來搭配使用
var userId = 123;
var cacheEntryOptions = new DistributedCacheEntryOptions
{
// Set AbsoluteExpiration for 3 mins
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(3),
// Set SlidingExpiration for 5 s
SlidingExpiration = TimeSpan.FromSeconds(5)
};
var info = await _distributedCache.GetOrCreateAsync(userId.ToString(), async () => await GetUserInfoFromDbAsync(), cacheEntryOptions);
}
擴充方法代碼如下:
public static async Task<TItem> GetOrCreateAsync<TItem>(this IDistributedCache cache, string key, Func<Task<TItem>> entity, DistributedCacheEntryOptions options = null)
{
// 如果快取 options 沒傳入則自動設定預設快取
if (options == null)
{
options = new DistributedCacheEntryOptions()
{
// 預設 5 分鐘快取
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(5)
};
}
// 取得快取資料,不存在則返回 null
var value = await cache.GetStringAsync(key);
// 不存在的情況
if (value == null)
{
// 透過傳入的委派 entity 取得 resource
var source = await entity();
// 序列化 json
var jsonSource = JsonSerializer.Serialize(source);
// 存入快取並同時回傳
await cache.SetStringAsync(key, jsonSource, options);
return source;
}
return JsonSerializer.Deserialize<TItem>(value);
}