ASP.Net MVC 延迟请求在客户端浏览器关闭后很久才到达

ASP.Net MVC Delayed requests arriving long after client browser closed

我想我知道这里发生了什么,但希望确认 and/or 阅读 material 可以将 "think" 变成 "know",实际问题在Tl,DR 部分 post 的结尾:

场景:

我正在测试我的 MVC 应用程序,以解决其中一个内部组件停止运行的情况(与我们的数据库的连接超时)。

在我的一个网页上有一个 Jquery 数据表,它每半秒通过 ajax 查询更新 - 我当前的任务是在数据请求超时时显示正确的错误.所以为了测试,我做了一个存储过程,要求数据库服务器在响应前等待 3 秒,这比配置的超时设置长 - 所以这保证了我捕获的超时异常。

我正在 Chrome 浏览器中测试一个客户端。正在 VS2013 IIS Express 中调试应用程序

问题: 没想到当我的故意减速被激活时会出现以下症状:

1) 启动带有操纵数据表的页面后,应用程序在处理来自客户端浏览器的所有请求时变慢了 - 还有 3 个其他组件发送 ajax 更新请求,与我故意破坏的组件并行,同样的减速也适用于我在 Web 应用程序中执行的任何会生成请求的操作(比如导航到其他页面)。浏览器的调试器显示请求按时发送,但服务器端相应的断点被击中的时间很晚(延迟超过 10 秒甚至几分钟)

2) 即使在我关闭应用程序的选项卡后,我的服务器仍继续处理请求。我关闭了浏览器,我确保 chrome.exe 进程已终止,但各种 Controller 操作的断点在 20 分钟后仍然被击中 - 主要是 "triggered" 通过自动循环 ajax 来自我在测试期间尝试访问的几个页面的请求。在我试图导航到的主页上也遇到了断点。在第二次测试中,我使用 RawCap 监控环回接口,以确保没有任何东西在后台发出请求 运行。

我想用另一种解释来确认或否定的理论:

所以上面的场景是以服务器无法处理的频率发出循环请求 - 客户端数据表循环每 .5 秒发送一次请求,每个请求至少需要 3 秒才能产生超时。显然在 IIS Express 的某个地方必须限制它能够处理的并发请求数...

让我感到惊讶的是,我假设如果达到该限制(我也假设存在),那么请求将被拒绝 - 相反,它们似乎在排队等待绝对无用的数量time to be processed later - 我的意思是,在什么情况下半小时后处理排队的 Web 请求会有用?

到目前为止我的问题是:

Tl,DR 问题:

IIS Express(Visual Studio 2013 附带)是否有并发连接限制?

如果是: { 这个限制是否可以在某处配置,如果是,在哪里?

IIS Express 如何处理达到该限制的情况 - 该处理是否也可以在某处配置? (我的意思是像排队 vs. 即时错误,比如服务器很忙) }

如果没有: { 当请求的速度快于处理速度时,服务器如何处理场景?可以在任何地方配置这种处理吗? }

这里 - http://www.iis.net/learn/install/installing-iis-7/iis-features-and-vista-editions

我发现 IIS7 至少允许无限数量的同步连接,但如果服务器速度不够快,无法处理所有请求,这实际上如何工作?是否可以在任何地方配置限制,以及如何处理达到该限制?

如果有任何指向在线阅读的链接,我们将不胜感激 material。

首先,这是一个简短的网络服务器 101。生产-class 网络服务器是多线程的,大致一个线程 = 一个请求。您通常会看到 Web 服务器的某种设置,称为 "max requests",这又大致对应于它可以生成的线程数。每个线程在 CPU 和 RAM 方面都有开销,因此在给定 运行 所在机器所拥有的资源的情况下,Web 服务器可以生成的数量存在一个非常实际的向上限制。

当 Web 服务器达到此限制时,它不会开始拒绝请求,而是将请求排队等待线程空闲后处理。例如,如果 Web 服务器的最大请求数为 1000(典型值),它突然被 1500 个请求轰炸。前 1000 个将立即处理,另外 500 个将排队,直到一些初始请求得到响应,释放线程并允许处理一些排队的请求。

此处的一个相关主题区域是异步,它在 Web 应用程序的上下文中允许线程在处于等待状态时返回到 "pool"。例如,如果您正在与 API 交谈,在发送请求和从 API 获得响应之间有一段等待时间,通常是由于网络延迟。如果您异步处理此问题,那么在此期间,线程可能会返回到池中以处理其他请求(例如上一个示例中的 500 个排队请求)。当 API 最终响应时,将返回一个线程以完成对请求的处理。异步允许服务器通过使用原本空闲的线程来处理新请求来更有效地处理资源。

然后,就是客户端-服务器的概念。在 HTTP 等协议中,客户端发出请求,服务器响应该请求。但是,两者之间没有持久的联系。 (从 HTTP 1.1 开始,这有点不真实。客户端和服务器之间的连接有时会持续存在,但这只是为了让未来更快 requests/responses,因为启动连接所需的时间不是一个因素。但是,在这种情况下,关于 client/server 的状态没有真正持续的沟通)。这里的要点是,如果客户端(如 Web 浏览器)向服务器发送请求,然后客户端关闭(例如关闭浏览器中的选项卡),则该事实不会传达给服务器。服务器所知道的就是它收到了一个请求并且必须响应,并且它会响应,即使从技术上讲另一端没有任何东西可以接收它。换句话说,仅仅因为浏览器选项卡已关闭,并不意味着服务器将停止处理请求并继续前进。

然后是超时。客户端和服务器都会有一些他们会遵守的超时值。 Internet 的分布式特性(由 TCP/IP 和 HTTP 等协议启用)意味着网络中的节点被假定为瞬态的。没有持久连接(除了上面的注释),并且在发出请求的客户端和响应请求的服务器之间可能会发生网络中断。如果client/server们没有这方面的打算,他们就只能一直坐在那里等下去了。但是,这些超时可能会有很大差异。服务器通常会在 30 秒内响应请求而超时(尽管可能会无限期设置)。 Web 浏览器等客户端往往更宽容一些,在某些情况下有 2 分钟或更长时间的超时。当服务器超时时,请求将被中止。根据 为什么 发生超时,客户端可能会收到各种错误响应。但是,当客户端超时时,通常不会通知服务器。这意味着如果服务器的超时时间高于客户端的超时时间,服务器 继续尝试响应,即使客户端已经继续进行。关闭浏览器选项卡可能会被视为客户端立即超时,但同样,服务器 none 更明智并继续尝试完成其工作。

所以,所有这一切归结起来就是这样。首先,在进行长轮询时(即每隔一段时间重复提交一个 AJAX 请求),您需要构建一个取消方案。例如,如果最后 5 个请求超时,您至少应该停止轮询一段时间。更好的办法是让一个 AJAX 请求的响应启动下一个请求。因此,您可以使用 setTimeout 并让 AJAX 回调启动它,而不是使用 setInterval 之类的东西。这样,只有在链条未断开时请求才会继续。如果一个 AJAX 请求失败,轮询会立即停止。但是,在那种情况下,您可能需要一些回退以在一段时间后重新启动请求链。这可以防止用新请求无休止地轰炸你已经失败的服务器。此外,轮询应该继续的时间应该总是有一些上限。如果用户让选项卡打开几天而不使用它,您真的应该一直轮询服务器吗?

在服务器端,您可以使用带有取消令牌的异步。这有两件事:1) 它为您的服务器提供了更多的喘息空间来处理更多的请求,以及 2) 它提供了一种在请求的某些部分超时时解除请求的方法。有关更多信息,请访问:http://www.asp.net/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4#CancelToken