- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如何在后台更新缓存以避免缓存未命中?
在 .net-core-2.1 中,我可以像这样添加内存缓存:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
}
}
那么使用起来就非常简单了:
[Route("api")]
public class DataController : Controller
{
private readonly IMemoryCache _cache;
private readonly DataContext _dataContext;
public DataController(IMemoryCache cache, DataContext dataContext)
{
_cache = cache;
_dataContext = dataContext;
}
[HttpGet]
[Route("GimmeCachedData")]
public async Task<IActionResult> Get()
{
var cacheEntry = await
_cache.GetOrCreateAsync("MyCacheKey", entry =>
{
entry.AbsoluteExpiration = DateTime.Now.AddSeconds(20);
return Task.FromResult(_dataContext.GetOrders(DateTime.Now));
});
return Ok(cacheEntry);
}
}
但是,在 20 秒的高速缓存 powered bliss infused 请求之后,正如预期的那样,缓存项已过期并且下一个请求因缓存未命中和后续数据加载而停止。
啊!所以缓存只是有时有效。为什么不能选择让它一直工作?
如何添加功能:
在尝试解决这个问题时,我在使用 IHostedService
的实现过程中遇到了 2 个主要障碍。 :
此缓存更新可以在注意到缓存未命中后直接启动,也可以通过主动监视下一个项目是否过期来启动。
我尝试使用 ConcurrentDictionary<String, CacheItem>
滚动我自己的缓存(将其添加为单例) . CacheItem
类包含 Value
的属性, Expiration
, 和一个 Factory
(即:值(value)返回代表)。但我发现,因为这个委托(delegate)可能是在请求时设置的,并在 IHostedService
中调用后台线程,它导致上下文超出范围异常。
最佳答案
我找到了一个似乎有效的解决方案。
ICache.UpdateCache
,如下所述),以避免请求时缓存未命中。public class CacheUpdateService : BackgroundService
{
private readonly ILogger<CacheUpdateService> _logger;
private readonly IServiceProvider _serviceProvider;
private readonly ICache _cache;
public CacheUpdateService(ILogger<CacheUpdateService> logger, IServiceProvider serviceProvider, ICache cache)
{
_logger = logger;
_serviceProvider = serviceProvider;
_cache = cache;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogDebug("CacheUpdateService is starting.");
stoppingToken.Register(Dispose);
while (!stoppingToken.IsCancellationRequested)
{
try
{
using (var scope = _serviceProvider.CreateScope())
{
var dataContext = scope.ServiceProvider.GetRequiredService<DataContext>();
// This tight loop calls the UpdateCache, which will block if no updates are necessary
await Task.Run(() => _cache.UpdateCache(dataContext), stoppingToken);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Exception in the CacheUpdateService");
}
}
_logger.LogDebug("CacheUpdateService has stopped.");
}
public override void Dispose()
{
using(var scope = _serviceProvider.CreateScope())
{
var scopedProcessingService = scope.ServiceProvider.GetRequiredService<ICache>();
// Dispose here on ICache will release any blocks
scopedProcessingService.Dispose();
}
base.Dispose();
}
}
Cache
下面的类实现了后台 UpdateCache
一次更新 1 个过期项目的方法。优先考虑最过期的。它还实现了请求范围的 GetOrCreate
方法。注意我在 Func<IDataContext, Object>
中使用委托(delegate)( CacheEntry
)作为值(value)人口工厂。这允许 Cache
注入(inject)适当范围的类 DataContext
(从 IHostedService
收到)并且它还允许调用者指定 DataContext
的哪个方法被调用以获取特定缓存键值的结果。注意我使用的是 AutoResetEvent
等待第一次数据填充以及启动下一次缓存刷新的计时器。此实现将在第一次调用该项目时遭受缓存未命中(我猜是在超过 1 小时未调用它之后;因为它将在 1 小时后被逐出。)。public class CacheEntry
{
public String Key { get; set; }
public Object Value { get; set; }
public Boolean Updating { get; set; }
public Int32 ExpirySeconds { get; set; }
public DateTime Expiration { get; set; }
public DateTime LastAccessed { get; set; }
public Func<IDataContext, Object> ValueFactory { get; set; }
}
public interface ICache : IDisposable
{
void UpdateCache(IDataContext dataContext);
T GetOrCreate<T>(String key, Func<IDataContext, T> factory, Int32 expirySeconds = 0) where T : class;
}
public class Cache : ICache
{
private readonly ILogger _logger;
private readonly ConcurrentDictionary<String, CacheEntry> _cache;
private readonly AutoResetEvent _governor;
public Cache(ILogger<Cache> logger)
{
_logger = logger;
_cache = new ConcurrentDictionary<String, CacheEntry>();
_governor = new AutoResetEvent(false);
}
public void Dispose()
{
_governor.Set();
}
public static Int32 CacheForHour => 3600;
public static Int32 CacheForDay => 86400;
public static Int32 CacheIndefinitely => 0;
public void UpdateCache(IDataContext dataContext)
{
var evictees = _cache.Values
.Where(entry => entry.LastAccessed.AddHours(1) < DateTime.Now)
.Select(entry => entry.Key)
.ToList();
foreach (var evictee in evictees)
{
_logger.LogDebug($"Evicting: {evictee}...");
_cache.Remove(evictee, out _);
}
var earliest = _cache.Values
.Where(entry => !entry.Updating)
.OrderBy(entry => entry.Expiration)
.FirstOrDefault();
if (earliest == null || earliest.Expiration > DateTime.Now)
{
var timeout = (Int32) (earliest?.Expiration.Subtract(DateTime.Now).TotalMilliseconds ?? -1);
_logger.LogDebug($"Waiting {timeout}ms for next expiry...");
_governor.WaitOne(timeout);
return;
}
try
{
_logger.LogDebug($"Updating cache for: {earliest.Key}...");
earliest.Updating = true;
earliest.Value = earliest.ValueFactory(dataContext);
earliest.Expiration = earliest.ExpirySeconds > 0
? DateTime.Now.AddSeconds(earliest.ExpirySeconds)
: DateTime.MaxValue;
_governor.Set();
}
finally
{
earliest.Updating = false;
}
}
public T GetOrCreate<T>(String key, Func<IDataContext, T> factory, Int32 expirySeconds = -1) where T : class
{
var success = _cache.TryGetValue(key, out var entry);
if (success && entry.Value != null)
{
entry.LastAccessed = DateTime.Now;
return (T) entry.Value;
}
if (entry == null)
{
_logger.LogDebug($"Adding new entry to the cache: {key}...");
entry = new CacheEntry
{
Key = key,
Expiration = DateTime.MinValue,
ExpirySeconds = expirySeconds,
LastAccessed = DateTime.Now,
ValueFactory = factory
};
_cache.TryAdd(key, entry);
_governor.Set();
}
while (entry.Value == null)
{
_logger.LogDebug($"Waiting for 1st time cache update: {entry.Key}...");
_governor.WaitOne();
}
return (T)entry.Value;
}
}
DataContext
然后像这样创建类。使用 Dapper
例如从数据库中检索数据:public class DataContext : DbContext, IDataContext
{
private readonly IOptions<Settings> _settings;
private String _databaseServer;
public DataContext(IOptions<Settings> settings)
{
_settings = settings;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer(_settings.Value.ConnectionString);
}
public IEnumerable<OrderInfo> GetOrders(DateTime date)
{
return Database.GetDbConnection().Query<OrderInfo>(
$"SchemaName.usp_GetOrders",
new {Date = date},
commandType: CommandType.StoredProcedure);
}
}
ICache
注入(inject)和使用如下: [HttpGet]
[Route("Orders/{date}")]
public IActionResult GetOrders(DateTime date)
{
var result = _cache.GetOrCreate(
$"GetOrders_{date:yyyyMMdd}",
context => context.GetOrders(date),
date.Date < DateTime.Today ? Cache.CacheIndefinitely : 20);
return Ok(result);
}
services.AddOptions();
services.Configure<Settings>(Configuration);
services.AddLogging();
services.AddDbContext<DataContext>();
services.AddSingleton<ICache, Cache>();
services.AddSingleton<IHostedService, CacheUpdateService>();
关于caching - 如何在 .net-core-2.1 中使用内存缓存避免缓存未命中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51451304/
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 8 年前。 Improve t
我卡在了一个点上,我无法进步,很抱歉这个愚蠢的问题。我为此进行了很多搜索,但我不知道我错过了什么。请帮助我。 我研究了 python 中的模块和类。现在我想使用 python 和 apt 进行一些操作
我在 Kong 有服务,我已经为该服务设置了代理缓存插件。 curl -X POST http://localhost:8001/plugins --data "name=proxy-cache"--
ASP.NET Core 提供内存缓存和响应缓存。 假设该应用程序是 ASP.NET Core WebAPI,它通过配置的响应缓存中间件将 SQL 数据库中的数据传送给用户。 在什么情况下也使用内存缓
我最近遇到了以下面试问题: You need to design a system to provide answers to factorials for between 1 and 100. Yo
我的 Javascript (JS) 代码遇到了一些麻烦,因为我有时需要在同一个函数中多次访问相同的 DOM 元素。还提供了一些推理here . 从性能的角度来看,是一次性创建一个 jQuery 对象
仅使用 Cache 终端,我使用或查看什么实用程序函数或 Global 来查找存在于 Cache 数据库中的所有 Globals 的列表? 再次仅在缓存终端中使用,我使用或查看什么实用程序功能或全局以
我的 Javascript (JS) 代码遇到了一些麻烦,因为有时我需要在同一个函数中多次访问同一个 DOM 元素。还提供了一些推理here . 从性能的角度来看,是先创建一个jQuery对象然后缓存
来自 RFC 2616 http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1 no-cache If the no-cach
大多数 CDN 服务器对经常访问的内容使用缓存。 场景:假设有人上传了一张非常热门的图片,并且来自同一位置的许多用户 (1000) 试图访问该图片。 问题:假设网络服务器收到一个请求,首先检查它的缓存
我的 Javascript (JS) 代码遇到了一些麻烦,因为有时我需要在同一个函数中多次访问同一个 DOM 元素。还提供了一些推理here . 从性能的角度来看,是先创建一个jQuery对象然后缓存
如果我将服务器响应设置为:Cache-Control: private,no-cache,max-age=900 ? 如果标题是这样的,会发生什么:Cache-Control: public,no-c
我有一个类需要在缓存中存储数据。最初我在 ASP.NET 应用程序中使用它,所以我使用了 System.Web.Caching.Cache。 现在我需要在 Windows 服务中使用它。现在,据我了解
我遇到了和这个人一样的问题:X-Drupal-Cache for Drupal 7 website always hits MISS ,并且找不到出路。 我正在运行 Drupal 7 - 新闻流 和
我已将 Laravel 设置为使用 Redis 作为缓存。当我使用 Cache::('my_var', 'my_val'); 然后通过 CLI 检查 Redis 以查看 key 是否已创建时,我可以验
我在 Windows Azure 云上有一个应用程序,并且正在使用 Windows Azure 共置缓存。 有时,当我发布网站/web服务时,调用DataCacheFactory.GetCache方法
我正在阅读 documentation for Apollo server-side caching ,但看不到任何关于缓存通常如何加密的内容。 我需要的是一个以响应中包含的对象 ID 为键的缓存,而
Hibernate\Grails 中最好的缓存策略是什么?是否缓存所有实体和查询以及如何找到最佳解决方案? 这是我的 hibernate 配置。 hibernate { cache.use_sec
我收到错误 'Nuget.Proxy Cache' 的类型初始化器抛出异常 尝试连接到 Nuget 官方包源时。我在公司网络后面,但是我怀疑问题是连接性。 有任何想法吗? 最佳答案 我有同样的问题。我
我是一名优秀的程序员,十分优秀!