【问题标题】:ASP.NET (MVC) Outputcache and concurrent requestsASP.NET (MVC) 输出缓存和并发请求
【发布时间】:2010-01-29 14:15:17
【问题描述】:

假设从理论上讲,我的网站中有一个页面/控制器操作,它执行了一些非常繁重的操作。完成它的操作大约需要 10 秒。

现在,我使用 .NET 的 outputcache 机制将其缓存 15 分钟(例如,我使用 [OutputCache(Duration = 900)])如果 15 分钟后缓存过期并且 100 个用户在这 10 秒内再次请求该页面会发生什么情况需要进行繁重的处理吗?

  1. 重的东西只做第一次,有一些锁定机制,让其他99个用户得到缓存结果
  2. 繁重的工作完成了 100 次(服务器瘫痪,因为它可能需要 100 * 10 秒)

也许是简单的问题,但我不能 100% 确定。不过我希望它是第一名:-)

谢谢!

【问题讨论】:

    标签: asp.net asp.net-mvc outputcache


    【解决方案1】:

    嗯,这取决于您如何配置 IIS。如果您的工作线程少于 100 个(比如说 50 个),那么“繁重的东西”会执行 50 次,从而削弱您的服务器,然后将从缓存中提供剩余的 50 个请求。

    但是不,缓存的动作结果没有“锁定机制”;在大多数情况下,这会适得其反。

    编辑:我相信这是真的,但 Nick 的测试结果并非如此,我现在没有时间测试。自己试试吧!不过,其余的答案并不依赖于上述内容,我认为它更重要。

    不过,一般来说,无论是缓存的还是其他方式的 Web 请求都不需要 10 秒才能返回。如果我站在你的立场上,我会以某种方式预先计算请求的困难部分。如果要缓存 HTML,您仍然可以缓存操作结果,但听起来您的问题比这要大一些。

    可能还想consider asynchronous controllers。最后,请注意,尽管 IIS 和 ASP.NET MVC 不会锁定这种繁重的计算,但您可以。如果您将异步控制器与计算锁定结合使用,那么您将有效地获得您所要求的行为。如果不知道更多关于你在做什么,我真的不能说这是否是最好的解决方案。

    【讨论】:

    • 谢天谢地,我真的没有需要 10 秒的请求,但为了说明一点,我大大夸大了。我只是好奇在这种情况下会发生什么。谢谢!不过可能会考虑实现异步控制器。
    • 已经有一段时间了......不过我自己做了一个测试,我确定它不会像你说的那样锁定。谢谢。
    【解决方案2】:

    这里好像卡住了,做个简单的测试:

    <%@ OutputCache Duration="10" VaryByParam="*" %>
    
    protected void Page_Load(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(new Random().Next(1000, 30000));
    }
    

    第一页到达那里的断点,即使它处于休眠状态...没有其他请求到达 Page_Load 方法中的断点...它等待第一个完成并将结果返回给所有请求的人页面。

    注意:这在 webforms 场景中更容易测试,但鉴于这是框架的一个共享方面,您可以在 MVC 中进行相同的测试并获得相同的结果。

    这是另一种测试方法:

    <asp:Literal ID="litCount" runat="server" />
    
    public static int Count = 0;
    
    protected void Page_Load(object sender, EventArgs e)
    {
      litCount.Text = Count++.ToString();
      System.Threading.Thread.Sleep(10000);
    }
    

    第一个请求进入睡眠状态时排队的所有页面将具有相同的计数输出。

    【讨论】:

    • 您在 WebDev 上进行测试吗?它的行为非常不同于多核服务器上的 IIS。
    • @Craig:在四核上使用 IIS 7.5、Windows 7 x64 进行测试
    • 这看起来很奇怪。也许您正在使用调试模式?这真的不应该锁定。其他请求应该会出现缓存未命中。
    • @Craig:不,发布模式...只是在 IIS 中附加调试器,但当然这可能会影响行为。另一方面,这将是最佳行为,因为 IIS 让其他请求等待并且都得到正在处理的第一个命中的结果。如果您指定输出缓存,您的意思是说您不希望这个东西经常处理,而 IIS 以这种方式行事将完成这一点,并且仍然尽快为每个请求提供服务(第一个请求的线程应该首先完成,在大多数情况下)。
    • 如果请求仍在处理中,即使第一个请求完成,下一个请求是否会命中缓存也不是很明显。我建议使用日志记录而不是调试器进行测试。
    【解决方案3】:

    老问题,但我遇到了这个问题,并做了一些调查。

    示例代码:

    public static int Count;
    [OutputCache(Duration = 20, VaryByParam = "*")]
    public ActionResult Test()
    {
        var i = Int32.MaxValue;
        System.Threading.Thread.Sleep(4000);
        return Content(Count++);
    }
    

    在一个浏览器中运行它,它似乎锁定并等待。

    在不同的浏览器中运行它(我在 IE 和 firefox 中测试过)并且请求没有被搁置。

    因此,“正确”的行为更多地与您使用的浏览器有关,而不是 IIS 中的功能。

    编辑:澄清 - 没有锁定。在缓存第一个结果之前,所有设法进入的请求都会攻击服务器,这可能会导致服务器因大量请求而受到重创。 (或者,如果您调用外部系统,如果您的服务器处理许多请求,该系统可能会被关闭......)

    【讨论】:

      【解决方案4】:

      我做了一个小测试,可能会有所帮助。我相信我发现的是未缓存的请求不会阻塞,并且在缓存过期和任务完成之前进入的每个请求也会触发该任务。

      例如,下面的代码在我使用 Cassini 的系统上大约需要 6-9 秒。如果您发送两个请求,大约相隔 2 秒(即两个浏览器选项卡),两者都会收到不同的结果。最后完成的请求也是为后续请求缓存的响应。

      // CachedController.cs
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Web;
      using System.Web.Mvc;
      
      namespace HttpCacheTest.Controllers
      {
          public class CachedController : Controller
          {
              //
              // GET: /Cached/
      
              [OutputCache(Duration=20, VaryByParam="*")]
              public ActionResult Index()
              {
                  var start = DateTime.Now;
      
                  var i = Int32.MaxValue;
                  while (i > 0)
                  {
                      i--;
                  }
                  var end = DateTime.Now;
      
                  return Content( end.Subtract(start).ToString() );
              }
      
          }
      }
      

      【讨论】:

        【解决方案5】:

        您应该检查此信息here: "您有一个客户端向服务器发出多个并发请求。默认行为是这些请求将被序列化;"

        所以,如果单个客户端的并发请求被序列化,后续的请求会使用缓存。这解释了一些行为似乎在上面的一些答案中(@mats-nilsson 和@nick-craver)

        您向我们展示的上下文是多个用户,它们将同时访问您的服务器,您的服务器将变得忙碌,直到完成至少一个请求并创建输出缓存,并将其用于下一个请求。所以如果你想序列化请求相同资源的多个用户,我们需要了解序列化请求是如何为单个用户工作的。这就是你想要的吗?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-01-20
          • 2011-01-22
          • 2010-09-27
          • 2013-04-20
          • 1970-01-01
          • 2020-09-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多