缓存过期时间早于预期

4

有人能在这里帮助我吗?我有以下代码来存储和检索缓存,但它不起作用。即使我将其设置为14天的slidingExpiration,缓存也会在几分钟后过期。提前感谢!

public static List<ReplyDTO> VideoCommentList()
{
     List<ReplyDTO> replyList = new List<ReplyDTO>();
     if (HttpRuntime.Cache["videoComment"] == null)
     {
         HttpRuntime.Cache.Remove("videoComment");
         HttpRuntime.Cache.Insert("videoComment", replyList, null, Cache.NoAbsoluteExpiration, TimeSpan.FromDays(14));
     }
     else
     {
         replyList = (List<ReplyDTO>)HttpRuntime.Cache["videoComment"];
     }

     if (replyList.Count > 8)
     {
         replyList = replyList.OrderByDescending(x => x.DateCreated).Take(8).ToList();
     }
     else
     {
         replyList = replyList.OrderByDescending(x => x.DateCreated).ToList();
     }
     return replyList;
}

public static List<ReplyDTO> AddVideoComment(ReplyDTO replyDTO)
{
     List<ReplyDTO> replyList = new List<ReplyDTO>();
     replyList = VideoCommentList();
     replyList.Add(replyDTO);
     HttpRuntime.Cache.Insert("videoComment", replyList, null, Cache.NoAbsoluteExpiration, TimeSpan.FromDays(14));

     if (replyList.Count > 8)
     {
          replyList = replyList.OrderByDescending(x => x.DateCreated).Take(8).ToList();
     }
     else
     {
          replyList = replyList.OrderByDescending(x => x.DateCreated).ToList();
     }
     return replyList;
}

请阅读此文档 - http://msdn.microsoft.com/zh-cn/library/xsbfdd8c(v=vs.100).aspx - KV Prajapati
5个回答

8

ASP.net缓存是内存中的,如果您的IIS进程或应用程序池重新启动,缓存将被清除。您可以检查以下可能导致进程重新启动的事项:

  • 如果您修改了web.config,IIS将关闭旧实例并慢慢将流量转移到新实例,在此过程中内存会被回收。 如何检查此情况: 您可以通过检查AppDomain.IsFinalizingForUnload并在回调期间记录来检测此情况。
  • 应用程序池回收:在IIS中有一个配置,根据该配置,如果IIS进程处于空闲状态一段时间,它将进行回收。您可以在服务器上检查此设置,并增加此时间或完全禁用回收。
  • 每个进程都有其可消耗内存量的限制,如果您向内存添加了太多的对象,它将增加IIS的内存消耗,并在关键时刻OS将回收进程。

编辑

在您的程序中,您正在将replyList项目添加到缓存中,然后执行.Take()操作。由于replyList是引用对象,如果您对其进行修改,缓存中的内容也会被更新。因此,如果在您的程序中执行replyList == null,它将更新缓存中的项目。

因此,请像这样修改您的代码并尝试

public static List<ReplyDTO> VideoCommentList()
{
    List<ReplyDTO> replyList = new List<ReplyDTO>();
    if (HttpRuntime.Cache["videoComment"] == null)
    {
        //Call to .Remove is not required
        //HttpRuntime.Cache.Remove("videoComment");
        HttpRuntime.Cache.Insert("videoComment", replyList, null,
                         Cache.NoAbsoluteExpiration, TimeSpan.FromDays(14));
    }
    else
    {
        //No need to check count > 8, Take will handle it for you
        replyList = ((List<ReplyDTO>)HttpRuntime.Cache["videoComment"])
                        .OrderByDescending(x => x.DateCreated)
                        .Take(8).ToList();
    }
    return replyList;
}

public static List<ReplyDTO> AddVideoComment(ReplyDTO replyDTO)
{
    //Read from cache
    List<ReplyDTO> replyList = ((List<ReplyDTO>)HttpRuntime.Cache["videoComment"]);
    if(replyList == null)
        replyList = VideoCommentList();
    replyList.Add(replyDTO);
    HttpRuntime.Cache.Insert("videoComment", replyList, null, Cache.NoAbsoluteExpiration, TimeSpan.FromDays(14));

    //Here you are creating a new list, and not referencing the one in the cache
    return replyList.OrderByDescending(x => x.DateCreated).Take(8).ToList();
}

重要建议

如果您想查看对象何时以及为什么被从缓存中删除,您可以在插入时使用CacheItemRemovedCallback选项来帮助您。通过使用此选项和CacheItemRemovedReason参数,您可以记录从缓存中删除对象的原因。原因如下:

  1. 已删除 - 您的代码调用了InsertRemove方法,将项目从缓存中移除。
  2. 过期 - 由于已过期,该项目已从缓存中删除。
  3. 未被使用 - 当系统内存不足时,它会通过从缓存中删除项目来释放内存。
  4. DependencyChanged - 与其相关联的缓存依赖项发生更改,因此从缓存中删除该项目。(在您的情况下无效)

希望这些信息对您有所帮助。


嗨,阿玛尔,我没有编辑任何文件。我认为IIS池没有回收,因为它只发生了几分钟。这是一个新站点,因此,现在我没有太多的流量。内存不应该是问题。你还能想到其他什么吗?谢谢。 - Jack
你检查了应用程序池回收时间吗?你怎么知道缓存已经刷新,你没有任何 CacheItemRemovedCallback - Amar Palsapure
1
是的,我确实使用了CacheItemRemovedCallback。我得到了“2-Removed”作为缓存被删除的原因。然而,我很惊讶对象引用在这里成为了问题。非常感谢您的回复。 - Jack
@Jack,您在这个问题上放了悬赏,谁赢得了它? - Amar Palsapure

1
为了追踪缓存中的项目被移除的原因,我建议您使用另一种重载的HttpRuntime.Cache.Insert方法,该方法允许您指定一个CacheItemRemovedCallback回调函数。 Cache.Insert Method (String, Object, CacheDependency, DateTime, TimeSpan, CacheItemPriority, CacheItemRemovedCallback) 除此之外,您的缓存代码似乎很好。但是一旦您更改代码以指定回调函数,请记录弹出原因,这可能会让您更好地了解为什么您的缓存项目被清除。
像其他答案一样,我怀疑您的应用程序由于各种原因而被重新启动/重置。我认为,在共享托管环境中,大多数生产机器上的应用程序每天至少重新启动一次。因此,我猜测您的数据最多只能在缓存中保存一天。

太遗憾了,我尝试使用回调函数进行处理,但当我的缓存消失时,我从中得到了值为0的结果。 - Jack
0 = 在 Microsoft.Practices.EnterpriseLibrary.Caching.CacheItemRemovedReason 中已过期,但在 System.Web.Caching.CacheItemRemovedReason 中没有定义 0。出于好奇,您是否尝试将滑动过期时间 TimeSpan 设置为 TimeSpan.FromMinutes(60) 等值,并查看其是否仍然过期?也许14天太长了。 - slolife
嗨,我已经尝试了removecallback并记录到数据库中。原因是2-已删除。对此有什么想法吗? - Jack
1
http://msdn.microsoft.com/en-us/library/system.web.caching.cacheitemremovedreason.aspx : 2 = 已删除,但这不是自动删除。它是手动删除,由您执行.Remove()调用或使用相同的缓存键名称调用.Insert()触发。您是否尝试插入许多项目,并且偶然尝试插入具有相同名称的项目?尝试将您的.Insert()调用更改为.Add(),如果键存在则失败,并查看是否解决了删除问题。请注意,这不是最终解决方案,而是一种跟踪问题的方法,如果您无法进行调试。 - slolife
@Jack 你可以尝试我的代码。我做了一些更改,也许可以处理这种情况。 - Amar Palsapure

0
在AddVideoComment()方法中,将缓存项插入行更改为:
  HttpRuntime.Cache.Insert("videoComment", replyList, null, Cache.NoAbsoluteExpiration, TimeSpan.FromDays(14),CacheItemPriority.NotRemovable,null);

在VideoCommentList()方法中使用:
       if (HttpRuntime.Cache["videoComment"] == null)
        {
            replyList = VideoCommentList(); 
            HttpRuntime.Cache.Insert("videoComment", replyList, null, Cache.NoAbsoluteExpiration, TimeSpan.FromDays(14),CacheItemPriority.NotRemovable,null);
        }

不需要使用HttpRuntime.Cache.Remove("videoComment");,因为HttpRuntime.Cache.Insert(会替换现有的缓存项。

祝好, DeveloperConcord


0

缓存是内存中的,当您的应用程序重新启动时会过期。我猜您正在开发机器上进行评估,其中流量较低或文件编辑导致应用程序重新启动。


嗨Simon,感谢您的回复。实际上,这是一个新网站并且是在共享托管环境中。我在测试期间几乎没有任何流量,此外,我也没有在那段时间编辑文件。 - Jack
嗯..你说共享主机?共享主机通常会关闭一段时间处于空闲状态的应用程序域,它们在第一次调用时重新激活。也许值得看一下AppDomain已经运行了多长时间https://dev59.com/-1HTa4cB1Zd3GeqPSIJy - vtortola

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接