首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >应用层排队/网站流量管理

应用层排队/网站流量管理
EN

Stack Overflow用户
提问于 2013-07-15 09:00:57
回答 7查看 4.4K关注 0票数 20

我们有一个网站应用程序,我们期望收到难以置信的高流量在几个点全年。我们目前有一些第三方负载平衡软件,它在繁忙期间将用户重定向到“持有”页面,以防止web应用服务器被传入的请求数量所窒息。

接下来,我们希望对这个过程有更多的控制,并实现某种类型的虚拟队列。当前负载均衡器没有排队功能,但只允许基于速率限制的流量通过。这是随机的,当您刷新页面(或自动刷新)时,这是很幸运的。

我在网上读了一些这方面的文章,但是很少发现关于如何实现一个非常基本的虚拟HTTP请求队列的实现细节。当然,有些公司将此作为一种成熟的服务提供,如排队-it网格法,但这些服务似乎过分满足了我们当前的需求(而且非常昂贵)。

所讨论的web应用程序是用ASP.Net MVC编写的。考虑到我们目前不需要诸如“队列优先级”等高级特性,我使用静态队列管理器类(使用ConcurrentQueue<T>等)创建了一个非常基本的概念证明,但我想知道这是否是一种有效的、可伸缩的方法?这是主要应用层的一部分吗?还是应该分开处理?有谁对如何在ASP.Net MVC应用程序中实现这种特性有任何技术诀窍吗?

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

之所以能够管理队列,是因为进程是非常的数据库--编写大量的。我们实际上是通过网站为某一特定产品创建订单。这意味着这些DB事务正在考虑诸如最后一分钟的股票检查等问题。这就是性能问题产生的原因,这也是想要实现某种排队系统的原因。

在数据库服务器上抛出更多的资源是不现实的选择。我真的在寻找这种性质的队列系统(C#或其他)的技术实现的详细信息。抱歉,如果最初没说清楚。

EN

回答 7

Stack Overflow用户

发布于 2013-07-20 17:36:19

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

  1. 缓存
  2. 无分割控制器
  3. AsyncControllers

输出缓存:

也许,(Performance-Wise)最有用的特性是输出缓存。当应用程序真正需要获取数据、对其进行计算并返回数据时,性能最大的会出现。输出缓存可以缓存这些结果,这样它们就可以直接返回,甚至不需要接触数据库。特别是在执行复杂查询时,这会显著降低服务器上的负载(实际上,您可以通过在web应用程序中谨慎地添加缓存来降低服务器上的负载90% )。

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
$(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");
    }
});

控制器-动作方法

代码语言:javascript
运行
复制
public class AjaxTestController : Controller
{       
    [HttpPost]
    public JsonResult Test(int? id)
    {
        Thread.Sleep(500);
        return Json(/*Some object*/);
    }
}

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

代码语言:javascript
运行
复制
[SessionState(SessionStateBehavior.Disabled)]
public class AjaxTestController : Controller
{       
    //...As above
}

好多了!您可以看到这3个请求是如何并行处理的,总共需要500 we才能完成,而不是我们在第一个示例中看到的1500 we。

异步控制器:

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

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

如何测量大流量下的响应时间?

我从这个链接复制了下面的内容。因为有时候链接断了所以我在这里保留了一些重要的部分。请查看此链接以获得更多详细信息。

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

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

结果说明了异步请求是如何执行的。查看这个平均响应时间与并发请求数量的关系图(较低的响应时间更好):

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

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

希望这能帮到你。

票数 26
EN

Stack Overflow用户

发布于 2013-07-15 10:20:00

IIS有自己的队列,您可以为每个应用程序池配置队列。下面是包含性能这里有用提示的链接。

我不会重新评论处理低技术性能优化的应用程序代码和代码。保持它的分离,因为它将使您的代码可访问。

票数 3
EN

Stack Overflow用户

发布于 2013-07-17 19:39:39

根据应用程序的不同,排队可能根本解决不了问题。如果您建立一个队列,您的服务器将有较少的工作要做的同时,因为较少的并发线程正在运行。

什么时候排队?

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

队列只是一个桶

正如你的问题所述,这一峰值持续时间超过几秒钟,“全年有几分”。因此,我假设您的服务器在一段时间内会遇到大量的新请求,这段时间足够长,以至于处理队列只会导致客户机超时。FYI:看看网络中的水桶模型。它们有同样的问题要处理。

让我举一个简单的例子:

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

由于高峰涌流只持续10分钟,所以您的排队时间最多可达20个客户端。

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

对于服务器上的峰值,这也是同样的问题:如果您不断地体验到更多无法处理的传入连接,您的队列将不断增长,直到它满了,然后丢弃传入的客户端。因此,通过排队,您只需延迟第一个被丢弃的客户端,并将其他客户端搁置(这也很烦人)。

回到现实世界的例子。这个问题如何在这里解决呢?这很容易:加快处理每个客户,或找一些职员,然后打开第二,第三,.队列一次处理多个客户端并处理所有订单。就像在现实世界和编程中一样:加速并不是那么容易。仅仅在短时间内建立多个实例也是很困难的。但说得很清楚:这是解决这些问题的唯一可靠办法。

使用IIS和MVC的:并不是在正确的位置排队,

在单个队列上排队,您可以在应用程序中构建一个队列,并在达到最大并发活动工人的情况下挂起所有涌入的请求。但这并不意味着在每个请求上生成和加载的所有插入tcp连接和asp会话都不存在开销,因为IIS接受新的连接,如果从IIS的角度有空闲的并发连接的话。

构建http代理应用程序

在单个或多个队列上排队--如果您正在构建一个自定义代理应用程序--您可能可以自行决定何时接受新的传入客户端连接(挂起tcp侦听器,或者在工作负载有足够资源处理新客户端之前不接受新客户端)。当然,您的代理可以将请求扩展到多个主机,并进行某种负载平衡--但这需要有额外的主机,您可以立即启动并处理请求(这是任何负载平衡器都需要您做的:拥有一个可能处理工作负载的后端)。由于这是一个绝对低水平的分配,我认为它不需要进一步的细节,并解释说,有很多风险时,走这条路。

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

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17650376

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档