【问题标题】:CacheManager - Refresh cache every x minutes or on expirationCacheManager - 每 x 分钟或到期时刷新缓存
【发布时间】:2018-05-16 07:49:31
【问题描述】:

使用CacheManager,您将如何最好地实施这种方案,其中缓存实例包含数据,可能需要很长时间才能从缓慢的来源获取?

我从不希望用户等待缓存填充(我不关心第一次加载)

我可以想到两种方法,但不确定是否可以使用 CacheManager:

“预定”刷新

  • 将缓存实例设置为 60 分钟后过期
  • 每 15 分钟安排一次刷新缓存实例的任务

到期刷新

  • 当缓存实例过期时,触发一个刷新数据的事件。在数据刷新时(或者如果刷新失败),缓存实例仍会返回“陈旧”数据。

Cachemanager 在技术上是可行的,哪种方法效果最好 - 如果有的话?

【问题讨论】:

    标签: c# .net caching cachemanager


    【解决方案1】:

    关于您的第二个选项“到期时刷新”,这不起作用,因为如果项目过期,CacheManager 不会返回缓存值。而且,当你“刷新”缓存时,你最终会从其他调用者那里得到很多缓存未命中。

    我的建议:

    如果您只有少量的密钥缓存了 60 分钟并且它们都“工作相同”,那么只需启动一个后台任务,该任务与您的进程异步运行并每 15 分钟刷新一次缓存。

    如果您有许多密钥,它们的过期时间可能会有很大差异,您可以缓存 60 分钟过期的数据并存储一个 15 分钟过期的辅助密钥(没有实际值的假密钥)。然后,如果假密钥过期,刷新实际的键/值... 如key 为假的,例如使用前缀+实际键,然后例如监听OnRemove 事件。

    快速示例程序

    internal class Program
    {
        private static ICacheManager<object> _cache;
    
        private static void Main(string[] args)
        {
            _cache = CacheFactory.Build(c => c.WithDictionaryHandle());
    
            _cache.OnRemoveByHandle += Cache_OnRemoveByHandle;
    
            for (var i = 0; i < 10; i++)
            {
                _cache.Add("key" + i, "data" + i);
                AddFakeKey("key" + i);
                Thread.Sleep(1000);
            }
    
            Console.ReadKey();
        }
    
        private static void AddFakeKey(string forKey)
        {
            _cache.Add(new CacheItem<object>("trigger_" + forKey, "n/a", ExpirationMode.Absolute, TimeSpan.FromSeconds(1)));
        }
    
        private static void Cache_OnRemoveByHandle(object sender, CacheItemRemovedEventArgs e)
        {
            // Remark: you might get this event triggered for each level of the cache e.Level can be checked to react only on the lowest level...
    
            Console.WriteLine("OnRemoveByHandle " + e.ToString());
            if (e.Key.StartsWith("trigger_") && e.Reason == CacheItemRemovedReason.Expired)
            {
                var key = e.Key.Substring(8);
                Console.WriteLine("Updating key " + key);
    
                // updating the key
                _cache.Update(key, _ => "new value");
    
                // add a new fake key for another round
                AddFakeKey(key);
            }
        }
    }
    

    如果启用了键空间通知,这甚至适用于 Redis。

    【讨论】:

      【解决方案2】:

      我没听懂你的“计划”刷新想法,为什么要将缓存设置为 60 分钟后过期并每 15 分钟刷新一次?

      如果我是你,我会这样做(有点像你的第二个想法):

      您第一次填充 CacheManager,然后每 60 分钟创建一个新的 CacheManager 实例(并填充它),如果一切顺利,您替换旧实例(您也将其丢弃)。

      我考虑过这一点,因为在 CacheManager 中,过期的项目不会被自动删除,所以它们仍然会存在,如果你决定做类似 [Populate-ClearAll-Populate-..] 的事情,那么你可能会进入一些问题,因此最安全的方法是在每次刷新时创建一个新实例,以确保您的缓存始终正常工作。

      【讨论】:

      • 15/60分钟的想法只是在缓存到期之前刷新缓存方式。 :)
      猜你喜欢
      • 2017-04-11
      • 2023-03-24
      • 2011-09-28
      • 2019-05-23
      • 2014-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多