.Net Core 緩存方式(二)分布式緩存
官方文檔
分布式緩存是由多個應用服務器共享的緩存,通常作為外部服務在訪問它的應用服務器上維護。 分布式緩存可以提高 ASP.NET Core 應用程序的性能和可伸縮性,尤其是在應用程序由雲服務或服務器場托管時。
與其他緩存方案相比,分布式緩存具有多項優勢,其中緩存的數據存儲在單個應用服務器上。
當分布式緩存數據時,數據將:
(一致性) 跨多個服務器的請求。
置服務器重啟和應用部署。
不使用本地內存。
IDistributedCache
IDistributedCache接口提供以下方法:
GetGetAsync:接受字符串鍵,並檢索緩存項作為 byte[] 數組(如果在緩存中找到)。
SetSetAsync:使用字符串鍵將項 (作為 byte[] 數組) 添加到緩存中。
Refresh, RefreshAsync :基於其鍵刷新緩存中的項,如果有任何) ,則重置其可調過期超時 (。
RemoveRemoveAsync:根據緩存項的字符串鍵刪除緩存項。
分布式內存緩存使用方式
Startup.ConfigureServices :
services.AddDistributedMemoryCache();
public class IndexModel : PageModel
{
private readonly IDistributedCache _cache;
public IndexModel(IDistributedCache cache)
{
_cache = cache;
}
public string CachedTimeUTC { get; set; }
public async Task OnGetAsync()
{
CachedTimeUTC = "Cached Time Expired";
var encodedCachedTimeUTC = await _cache.GetAsync("cachedTimeUTC");
if (encodedCachedTimeUTC != null)
{
CachedTimeUTC = Encoding.UTF8.GetString(encodedCachedTimeUTC);
}
}
public async Task<IActionResult> OnPostResetCachedTime()
{
var currentTimeUTC = DateTime.UtcNow.ToString();
byte[] encodedCurrentTimeUTC = Encoding.UTF8.GetBytes(currentTimeUTC);
var options = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(20));
await _cache.SetAsync("cachedTimeUTC", encodedCurrentTimeUTC, options);
return RedirectToPage();
}
}
實現方式
Microsoft.Extensions.Caching.Abstractions/src/IDistributedCache.cs
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.Extensions.Caching.Distributed
{
/// <summary>
/// Represents a distributed cache of serialized values.
/// </summary>
public interface IDistributedCache
{
/// <summary>
/// Gets a value with the given key.
/// </summary>
/// <param name="key">A string identifying the requested value.</param>
/// <returns>The located value or null.</returns>
byte[] Get(string key);
/// <summary>
/// Gets a value with the given key.
/// </summary>
/// <param name="key">A string identifying the requested value.</param>
/// <param name="token">Optional. The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the located value or null.</returns>
Task<byte[]> GetAsync(string key, CancellationToken token = default(CancellationToken));
/// <summary>
/// Sets a value with the given key.
/// </summary>
/// <param name="key">A string identifying the requested value.</param>
/// <param name="value">The value to set in the cache.</param>
/// <param name="options">The cache options for the value.</param>
void Set(string key, byte[] value, DistributedCacheEntryOptions options);
/// <summary>
/// Sets the value with the given key.
/// </summary>
/// <param name="key">A string identifying the requested value.</param>
/// <param name="value">The value to set in the cache.</param>
/// <param name="options">The cache options for the value.</param>
/// <param name="token">Optional. The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken));
/// <summary>
/// Refreshes a value in the cache based on its key, resetting its sliding expiration timeout (if any).
/// </summary>
/// <param name="key">A string identifying the requested calue.</param>
void Refresh(string key);
/// <summary>
/// Refreshes a value in the cache based on its key, resetting its sliding expiration timeout (if any).
/// </summary>
/// <param name="key">A string identifying the requested value.</param>
/// <param name="token">Optional. The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
Task RefreshAsync(string key, CancellationToken token = default(CancellationToken));
/// <summary>
/// Removes the value with the given key.
/// </summary>
/// <param name="key">A string identifying the requested value.</param>
void Remove(string key);
/// <summary>
/// Removes the value with the given key.
/// </summary>
/// <param name="key">A string identifying the requested value.</param>
/// <param name="token">Optional. The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
Task RemoveAsync(string key, CancellationToken token = default(CancellationToken));
}
}
AddDistributedMemoryCache 的實現
- Microsoft.Extensions.Caching.Memory/src/MemoryCacheServiceCollectionExtensions.cs 依賴注入 IDistributedCache與 MemoryDistributedCache實現
public static IServiceCollection AddDistributedMemoryCache(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.AddOptions();
services.TryAdd(ServiceDescriptor.Singleton<IDistributedCache, MemoryDistributedCache>());
return services;
}
- MemoryDistributedCache : IDistributedCache
Microsoft.Extensions.Caching.Memory/src/MemoryDistributedCache.cs
namespace Microsoft.Extensions.Caching.Distributed
{
public class MemoryDistributedCache : IDistributedCache
{
private readonly IMemoryCache _memCache;
public MemoryDistributedCache(IOptions<MemoryDistributedCacheOptions> optionsAccessor)
: this(optionsAccessor, NullLoggerFactory.Instance) { }
public MemoryDistributedCache(IOptions<MemoryDistributedCacheOptions> optionsAccessor, ILoggerFactory loggerFactory)
{
if (optionsAccessor == null)
{
throw new ArgumentNullException(nameof(optionsAccessor));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_memCache = new MemoryCache(optionsAccessor.Value, loggerFactory);
}
public byte[] Get(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return (byte[])_memCache.Get(key);
}
public Task<byte[]> GetAsync(string key, CancellationToken token = default(CancellationToken))
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return Task.FromResult(Get(key));
}
public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
var memoryCacheEntryOptions = new MemoryCacheEntryOptions();
memoryCacheEntryOptions.AbsoluteExpiration = options.AbsoluteExpiration;
memoryCacheEntryOptions.AbsoluteExpirationRelativeToNow = options.AbsoluteExpirationRelativeToNow;
memoryCacheEntryOptions.SlidingExpiration = options.SlidingExpiration;
memoryCacheEntryOptions.Size = value.Length;
_memCache.Set(key, value, memoryCacheEntryOptions);
}
public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken))
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
Set(key, value, options);
return Task.CompletedTask;
}
public void Refresh(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
_memCache.TryGetValue(key, out object value);
}
public Task RefreshAsync(string key, CancellationToken token = default(CancellationToken))
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
Refresh(key);
return Task.CompletedTask;
}
public void Remove(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
_memCache.Remove(key);
}
public Task RemoveAsync(string key, CancellationToken token = default(CancellationToken))
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
Remove(key);
return Task.CompletedTask;
}
}
}