Caching 如何使用.net-core-2.1中的内存缓存避免缓存未命中
如何在后台更新缓存以避免缓存未命中 在.net-core-2.1中,我可以添加一个内存缓存,如下所示:Caching 如何使用.net-core-2.1中的内存缓存避免缓存未命中,caching,asp.net-core-2.0,Caching,Asp.net Core 2.0,如何在后台更新缓存以避免缓存未命中 在.net-core-2.1中,我可以添加一个内存缓存,如下所示: 公共类启动 { public void配置服务(IServiceCollection服务) { services.AddMemoryCache(); } } 然后,使用起来非常简单: [路由(“api”)] 公共类DataController:控制器 { 专用只读IMemoryCache\u缓存; 私有只读数据上下文_DataContext; 公共DataController(IMe
公共类启动
{
public void配置服务(IServiceCollection服务)
{
services.AddMemoryCache();
}
}
然后,使用起来非常简单:
[路由(“api”)]
公共类DataController:控制器
{
专用只读IMemoryCache\u缓存;
私有只读数据上下文_DataContext;
公共DataController(IMemoryCache缓存、DataContext DataContext)
{
_缓存=缓存;
_dataContext=dataContext;
}
[HttpGet]
[路线(“Gimmecachedata”)]
公共异步任务Get()
{
var cacheEntry=wait
_getorCreateAync(“MyCacheKey”,条目=>
{
entry.AbsoluteExpiration=DateTime.Now.AddSeconds(20);
返回Task.FromResult(_dataContext.GetOrders(DateTime.Now));
});
返回Ok(缓存条目);
}
}
然而,正如预期的那样,经过20秒速度惊人的高速缓存的powered bliss infused请求后,缓存项过期,下一个请求由于缓存未命中和后续数据加载而暂停
啊!因此,缓存只在某些时候起作用。为什么不让它一直工作呢
如何将功能添加到:
IHostedService实现时遇到了两个主要障碍:
当缓存项过期时,它将被逐出,不再可用;意思是我不能退
更新需要数据库的缓存项会导致这些调用超出范围
此缓存更新可以在发现缓存未命中后直接启动,也可以通过主动监视下一个即将过期的项来启动
我曾尝试使用ConcurrentDictionary
滚动我自己的缓存(将其作为单例添加)。CacheItem
类包含值
、到期
和工厂
(即:值返回委托)的属性。但我发现,由于此委托可能是在请求时设置的,并在IHostedService
后台线程中调用,因此它导致了上下文超出范围异常。我找到了一个似乎可行的解决方案
实现IHostedService(从类扩展)。此类将用作.net核心框架管理的后台线程。后台线程将保持缓存更新运行(通过调用ICache.UpdateCache
,如下所述),以避免请求时缓存命中
公共类CacheUpdateService:BackgroundService
{
专用只读ILogger\u记录器;
私有只读服务器ViceProvider\u服务提供商;
专用只读ICache\u缓存;
公共缓存更新服务(ILogger记录器、IServiceProvider服务提供商、ICache缓存)
{
_记录器=记录器;
_服务提供者=服务提供者;
_缓存=缓存;
}
受保护的覆盖异步任务ExecuteAsync(CancellationToken stoppingToken)
{
_LogDebug(“CacheUpdateService正在启动”);
停止通话。登记(处理);
同时(!stoppingToken.IsCancellationRequested)
{
尝试
{
使用(var scope=\u serviceProvider.CreateScope())
{
var dataContext=scope.ServiceProvider.GetRequiredService();
//这个紧密循环调用UpdateCache,如果不需要更新,它将被阻止
等待任务。运行(()=>_cache.UpdateCache(dataContext),stoppingToken);
}
}
捕获(例外情况除外)
{
_logger.LogError(例如,“CacheUpdateService中的异常”);
}
}
_LogDebug(“CacheUpdateService已停止”);
}
公共覆盖无效处置()
{
使用(var scope=\u serviceProvider.CreateScope())
{
var scopedProcessingService=scope.ServiceProvider.GetRequiredService();
//在ICache上此处进行处理将释放任何块
scopedProcessingService.Dispose();
}
base.Dispose();
}
}
下面的Cache
类实现后台UpdateCache
方法,该方法将一次更新1个过期项目。优先处理最过期的一个。它还实现了请求范围GetOrCreate
方法。注意,我使用CacheEntry
中的委托(Func
)作为值填充工厂。这允许Cache
类插入范围正确的DataContext
(从IHostedService
接收),还允许调用者指定调用DataContext
的哪个方法以获得特定缓存键值的结果。请注意,我正在使用一个AutoResetEvent
来等待第一次数据填充以及启动下一次缓存刷新的计时器。此实现将在第一次调用该项时发生缓存未命中(我猜是在该项未被调用超过1小时之后;因为它将在1小时后被逐出)
公共类缓存条目
{
公共字符串密钥{get;set;}
公共对象值{get;set;}
公共布尔更新{get;set;}
公共Int32 ExpirySeconds{get;set;}
公共日期时间过期{get;set;}
上次访问的公共日期时间{get;set;}
public Func ValueFactory{get;set;}
}
公共接口ICache:IDisposable
{
void UpdateCache(IDataContext数据上下文);
T GetOrCreate(字符串键,函数工厂,Int32 expirySec