应用程序级排队/网站流量管理

时间:2013-07-15 09:00:58

标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-4

我们有一个网站应用程序,我们希望在全年的几个点上获得令人难以置信的高流量。我们目前有一些第三方负载平衡软件,可以在繁忙时段将用户重定向到“保留”页面,以防止我们的Web应用程序服务器被请求的数量所窒息。

展望未来,我们希望能够更好地控制此流程并实现某种虚拟队列。当前负载均衡器没有排队功能,但只允许基于速率限制的流量。这是随机的,当你刷新页面(或者自动刷新)时,它会很好运。

我已经在网上阅读过这方面的内容,但发现了很少有关如何实现非常基本的虚拟HTTP请求队列的实现细节。当然,有些公司会将此作为完全成熟的服务提供,例如queue-itNetprecept,但这些服务对我们当前的需求来说似乎有些过分(并且非常昂贵)。

有问题的Web应用程序是用ASP.Net MVC编写的。请记住,我们现在不需要像“队列优先级”等高级功能,我使用静态队列管理器类,使用ConcurrentQueue<T>等创建了一个非常基本的概念验证。想知道这是否是一种有效的,可扩展的方法?这是否可以成为主要应用层的一部分?还是应该分开?有没有人知道如何在ASP.Net MVC应用程序中实现这种功能?


编辑:感谢目前为止的答案。大多数答案似乎都涉及很多关于缓存的细节。这已经(非常)在我们的网站上大量使用,使用ASP.Net网络缓存,在负载均衡器级别缓存整页请求和使用AppFabric进行对象缓存。

管理队列能力的原因是因为该过程非常数据库重写。我们通过网站有效地为某个产品创建订单。这意味着这些数据库事务正在考虑事项,例如最后一刻的库存检查等。这就是性能问题出现的地方,这就是想要实现某种排队系统的原因。

在数据库服务器上投入更多资源并不是一个现实的选择。我真的在寻找这种排队系统(C#或其他)的技术实现细节。对不起,如果最初没有说清楚。

7 个答案:

答案 0 :(得分:25)

您在考虑应用程序的性能时是否考虑以下几点?

  1. 缓存
  2. 无会话控制器
  3. AsyncControllers
  4. 输出缓存:

    MVC3( Performance-Wise )最有用的功能可能是输出缓存。当您的应用程序确实需要获取数据,对其进行计算并返回数据时,实际上会发生最大的性能命中。输出缓存可以缓存这些结果,因此可以直接返回它们,甚至无需触及数据库。特别是在执行复杂查询时,这会显着降低服务器上的负载(实际上,您可以通过在Web应用程序中仔细调整缓存来减少90%的负担)。

    namespace MvcApplication1.Controllers
    {
         public class DataController : Controller
         {
              [OutputCache(Duration=10)]
              public string Index()
              {
                   return DateTime.Now.ToString("T");    
              }
         }
    }
    

    无会话控制器:

    禁用会话状态的控制器为不需要会话状态的控制器提供优化。无状态控制器适用于您不需要会话概念的情况。

    默认情况下,ASP.NET管道不会同时处理属于同一会话的请求。它将它们串行化,即它按照它们被接收的顺序对它们进行排队,以便它们被串行处理而不是并行处理。这意味着如果请求正在进行且来自同一会话的另一个请求到达,则它将排队等待仅在第一个请求完成时开始执行。

    让我们看一个例子;一个页面向服务器发出3个异步AJAX请求,启用了会话状态(还要注意,实际上必须使用会话,因为如果你从不使用会话状态,ASP.NET足够智能,不会序列化请求,即使它是启用)。

    <强> JQuery的

    $(document).ready(function () {
        //Make 3 concurrent requests to /ajaxtest/test
        for (var i = 0; i < 3; i++) {       
            $.post("/ajaxtest/test/" + i,
                function (data) {                       
                    //Do something with data...
                },
                "json");
        }
    });
    

    控制器 - 操作方法

    public class AjaxTestController : Controller
    {       
        [HttpPost]
        public JsonResult Test(int? id)
        {
            Thread.Sleep(500);
            return Json(/*Some object*/);
        }
    }
    

    enter image description here

    您可以在网络配置文件中看到序列化请求的效果;每个请求比前一个请求大约长500毫秒。因此,这意味着我们不能通过异步进行这些AJAX调用获得任何好处。让我们的AjaxTestController禁用会话状态再次查看配置文件(使用[SessionState]属性)。

    [SessionState(SessionStateBehavior.Disabled)]
    public class AjaxTestController : Controller
    {       
        //...As above
    }
    

    enter image description here

    好多了!您可以看到3个请求是如何并行处理的,并且总共花费500毫秒来完成,而不是我们在第一个示例中看到的1500毫秒。

    异步控制器:

    首先,控制器开始一个或多个外部I / O调用(例如,SQL数据库调用或Web服务调用)。在不等待它们完成的情况下,它会将线程释放回ASP.NET工作线程池,以便它可以处理其他请求。

    稍后,当所有外部I / O调用完成后,底层ASP.NET平台会从池中获取另一个空闲工作线程,将其重新挂接到原始HTTP上下文,并让它完成处理原始请求。 / p>

    enter image description here

    How to Measure the Response time under Heavy Traffic?

    I copied below content from this link. Because sometime links gets broken so I kept some important part here. Please check this link for more details

    要了解异步控制器如何响应不同级别的流量,以及如何与简单的同步控制器进行比较,您可以创建一个带有两个控制器的示例MVC。为了模拟长时间运行的外部,它们都执行一个需要2秒才能完成的SQL查询(使用SQL命令WAITFOR DELAY '00:00:02')然后它们将相同的固定文本返回给浏览器。其中一个是同步的;另一个异步。

    在另一个示例中,您可以检查一个简单的C#控制台应用程序,该应用程序模拟大量流量命中给定的URL。它只是一遍又一遍地请求相同的URL,计算最后几个响应时间的滚动平均值。首先它只在一个线程上执行,但随后在30分钟内逐渐将并发线程数增加到150。如果您想尝试在自己的网站上运行此工具,可以下载C#源代码。

    结果说明了有关异步请求如何执行的许多要点。查看平均响应时间与并发请求数的图表(响应时间越短越好):

    enter image description here

    要理解这一点,首先我需要告诉您,我已将ASP.NET MVC应用程序的工作线程池设置为人为的最低限制为50个工作线程。我的服务器实际上有一个默认的最大线程池大小200 - 一个更明智的限制 - 但如果我减少它的结果会更清楚。 正如您所看到的,只要有足够的工作线程可以执行,同步和异步请求的执行完全相同。他们为什么不应该呢? 但是一旦线程池耗尽(&gt; 50个客户端),同步请求就必须形成一个要服务的队列。基本排队理论告诉我们,队列中等待的平均时间由公式给出:

    enter image description here

    这正是我们在图表中看到的。排队时间随着队列的长度线性增长。 (为我放纵使用公式而道歉 - 有时候我无法压抑我内心的数学家。如果成为一个问题,我会接受治疗。) 但是,异步请求不需要这么快就开始排队。它们不需要在等待时阻塞工作线程,因此线程池限制不是问题。那么,当有超过100个客户时,为什么他们会开始排队?这是因为ADO.NET连接池默认限制为100个并发连接。

    希望这对你有所帮助。

答案 1 :(得分:3)

IIS拥有自己的队列,您可以为每个应用程序池配置它们。以下链接包含有关效果 here 的有用提示。

我不建议混合使用低技术性能优化的应用程序代码和代码。保持它是分开的,因为它将使你的代码保持可持续性。

答案 2 :(得分:2)

根据您的应用程序排队可能根本无法解决您的问题。 如果构建队列,则服务器将同时执行的工作较少,因为并发线程的运行较少。

何时排队?

显然我要扭转这个问题:你为什么要排队? 可能是因为您的服务器无法处理传入流量。如果我们谈论的峰值只持续几秒钟,这不是什么大问题:建立一个队列并在几秒钟内处理它。

队列只是一个存储桶

正如你的问题所说,这个峰值的持续时间超过了几秒钟“全年有几个点”。因此,我假设您的服务器正在经历大量涌现的新请求,这段时间足够长,以至于处理队列只会导致客户端超时。 [仅供参考:查看网络中的桶模型。这些问题有待处理]

让我举一个简单的例子:

这是夏天的正常日子,你在街角提供冷柠檬水。您每分钟最多可以处理5个客户,午餐时间的高峰意味着大约有7个客户每分钟排队等待您的柠檬水。一分钟后,你有2个客户等待,两分钟后你有4个客户等着你处理他们的订单[等等]。

由于峰值突然只是暂停,比方说10分钟,你的队列最多只能达到20个客户。

另一天,非常热,你的浪涌峰值不是通常的每分钟7个客户,你的浪涌达到每分钟42个客户。 这意味着一分钟后你就有37位客户在等你的柠檬水。 很明显 - 除了它是地球上最后一个柠檬水之外 - 你的客户不会排队一小时喝一杯柠檬水而只会离开。

这与您在服务器上的峰值有关的问题:如果您不断遇到更多传入连接,您的队列将会增长,直到它已满,然后丢弃传入的客户端。因此,排队获得的只是你只是延迟了第一批被丢弃的客户端并将其他客户端置于保持状态(这也很烦人)。

回到现实世界的例子。这个问题怎么解决? 它非常简单:加快处理每个客户端或获得一些职员并打开第二个,第三个......队列来同时处理多个客户端并处理所有订单。 就像在现实世界和编程中一样:加速并不容易。短时间内起床多个实例也很安静。但清楚地说:这些是处理此类问题的唯一可靠解决方案。

使用IIS和MVC:并非真正排队在正确的位置

[在单个队列中排队]您可以在应用程序中构建一个队列,并在您达到最大并发活动工作时暂停所有入侵请求。但这并不意味着所有进入的tcp连接和asp会话都没有开销,因为如果从IIS的角度看有可用的并发连接,IIS会接受新的连接,因此会在每个请求上生成并加载。

构建http代理应用程序

[在单个或多个队列上排队]如果您正在构建自定义代理应用程序,您可以自己决定何时接受新的传入客户端连接(暂停tcp侦听器或仅接受新客户端工作负载有足够的资源来处理新客户端)。当然,您的代理可以将请求分散到多个主机并进行某种负载平衡 - 但这需要您有其他主机,您可以立即启动并处理请求(这是任何负载均衡器需要您:具有后端这可能会处理工作量)。 由于这是一个绝对低水平的应用程序,我认为不需要进一步详细说明并解释在走这条路时存在很多风险。

关于减少部分部分工作负载的一些简单方面: - 将图像等静态内容卸载到低成本的其他服务器/站点。这样可以减少主服务器上的工作量,从而完成艰苦的动态工作。 - 缓存:不要做两次具有相同结果的事情。检查应用程序在高工作负载中变慢的位置,并尝试尽可能快地优化它们。 - 工作异步/将长跑者置于睡眠状态:如果您有外部请求(数据库),请尝试以异步方式实现它们,使您的线程尽可能长时间运行,然后进入睡眠状态,为主机的调度程序提供有机会处理其他待处理的工作。对线程进行基准测试,检查关键方法的包容时间以及花费时间的时间。

希望这有助于解决您的问题,或者让您知道应该走哪条路。

答案 3 :(得分:1)

我建议您使用 BIG-IP 之类的内容,如果您打算使用基于软件的方法,那么您将基于Redirect的基础您对服务器的请求?有许多选择,如 Round Robin ..等等

Take a look at this article if it helps

答案 4 :(得分:0)

您可以查看获取一些基准数据,以了解当前设置(基础架构和应用程序)可以处理的负载/流量类型,例如有多少并发用户等。

您可以使用Microsoft Team Foundation Service(托管在云中,与托管在内部的TF Server不同,即您的基础架构。使用 Load/Stress/Performance tests

执行此操作

我认为TFS服务对于我认为小于5位开发人员的开发团队是免费的。不要引用我: - )

一旦你得到一些球场数据,如果你的应用程序可以应付,那么无事可做。如果它不能做出一些决定呢?你当时的80/20场景。是否值得将80%的资源(开发时间,工资等)用于可能的20%性能增益,或者更好地投入20%的硬件成本(CPU,RAM,另一台服务器等)以实现80%的即时性能提升?

如果此网站对您的企业或客户而言非常重要,并且正在创造收入或具有立法目的,那么您可能会发现投资硬件更容易投资软件开发。这样,您可以在没有单点故障(SPF)的情况下拥有高可用性(HA)可扩展应用程序。

不是真正回答你的排队问题,而只是另一个需要考虑的观点。

仅供参考我们希望升级到运行Windows Server 2012企业版的两个VM(运行VMWare)前端Web服务器。这些将使用microsoft NLB进行网络负载平衡(因此不需要其他负载平衡服务器或第三方软件)。我们将为备份的SQL服务器提供一个主动 - 主动群集。这使我们可以在不停机的情况下维护服务器(升级,补丁等)。另一个好处是IIS 8.0可以使用SNI运行相同IP的多个域(主机)进行SSL(HTTPS)流量,这很好(但是鱼雷用户运行的是windows xp,但是无论如何它在2014年4月都没有支持)。我们必须升级.net应用程序以处理会话管理和MACstate(跨服务器回发等),但交易是值得的。

答案 5 :(得分:0)

除了PKKG的答案之外,您还必须重新设计应用程序的某些部分以添加缓存。

ASP.NET MVC输出缓存支持 SQL缓存依赖,它允许您根据表中的某个版本列由服务器和客户端缓存页面。

假设您有一个频繁显示的页面,但更改频率较低。例如,Stack Overflow的Question页面。每个问题可能有1:100写入与读取操作。这意味着对于每次读取,连接到DB的成本都非常高。

所以我们可以做的是,将LostUpdate列视为Version列,并在此页面上添加SQL Cache Dependency,其中SQL查询返回true如果当前问题的LastUpdate晚于给定的缓存时间。

对于每一页,Cache Manager都会对SQL进行缓存查询,但此查询比整个页面小,因为页面包含大量查询到不同的表以及构建和显示每个信息。例如,答案,他们的作者和他们的声誉等。因此,对于100次,只有一个LostUpdate查询可以节省大量开销,而不是所有多个查询的100倍。加入&amp;许多其他计算。

在每个页面上执行此操作很困难,但您可以分析流量模式并改进缓存。在使用Stake Overflow的相同示例中,主页上的缓存可能是坏主意,因为它显示最近更新的条目,因此缓存可能不起作用,因为页面更改太快。

答案 6 :(得分:0)

一些选项是使用sql service broker或复制快照。使用快照,您可以将报告进程移动到数据库的其他副本,并使锁定保持较低。