【问题标题】:Speeding up the rate that IIS/.NET/LINQ retrieves data from the Network Buffers加快 IIS/.NET/LINQ 从网络缓冲区检索数据的速度
【发布时间】:2011-03-03 00:32:22
【问题描述】:

在对我的 Web 服务器和数据库服务器之间的流量进行 TCP 分析时,我发现网络缓冲区(TCP 窗口)经常被填满。然后,Web 服务器向数据库服务器发送 TCP 消息,告诉它其缓冲区已满,并且在获得更新之前不要发送更多数据。

例如,这是网络缓冲区的大小(以字节为单位),用于一段时间内与数据库服务器的长期连接:

Web 服务器在 Windows 2008 R2 Web 服务器上运行以 IIS 集成模式运行的 .NET 4.0 应用程序。 SQL 服务器是 2008 R2 服务器。

我对此的解释是,SQL 服务器向 Web 服务器返回数据的速度比 Web 服务器上的应用程序可以从缓冲区收集数据的速度更快。我已经尝试调整网络驱动程序中的所有内容来解决这个问题。特别是增加 RSS 队列、禁用中断调节以及设置 Windows 2008 R2 服务器以更积极地增加缓冲区大小。

因此,如果我的解释是正确的,那让我想知道两种可能性:

  1. .NET 中有没有办法告诉它增加网络缓冲区的大小? “增强的 2008 R2 TCP 堆栈”很少决定为此连接启用窗口缩放(使缓冲区大于 65 kBytes)(可能是由于低延迟)。看起来手动设置这个系统范围的能力在 Windows server 2008 r2 中消失了(曾经有现在被忽略的注册表项)。那么有没有办法可以在代码中强制执行此操作?
  2. 是否有任何可以调整的东西来加快应用程序读取网络缓冲区信息的速度,尤其是 SQL 连接?

编辑:
请求的 DMV 查询在 ASYNC_NETWORK_IO 处中断:

SELECT * FROM sys.dm_os_wait_stats ORDER BY waiting_tasks_count desc;
wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms CXPACKET 1436226309 2772827343 39259 354295135 睡眠任务 231661274 337253925 10808 71665032 LATCH_EX 214958564 894509148 11855 84816450 SOS_SCHEDULER_YIELD 176997645 227440530 2997 227332659 ASYNC_NETWORK_IO 112914243 84132232 16707 16250951

【问题讨论】:

  • 这是一个我将直接与 Microsoft 讨论的问题。打开支持票证或使用免费的 MSDN 电话(如果有)。

标签: .net sql linq tcp buffer


【解决方案1】:

1) 是什么让您认为这是 TCP 流量控制,而不是 SQL Server 在没有流量的时间间隔内不生成数据?检查sys.dm_exec_requests 是否查看wait_type。等待类型在Waits and Queues 中描述。如果确实是客户端应用 TCP 流控,那么你会看到等待类型ASYNC_NETWORK_IO

2) 如果问题确实是网络等待类型,那么解决方法不是增加带宽,而是明显减少流量。客户端没有业务向服务器请求太多数据以导致 TCP 流控制。这可能是由于在客户端中执行了可怕的错误操作,例如计算行数或客户端分页。将处理转移到服务器上,只需获得包含所需数据的小型结果集。

编辑

使用 DB 调用结果集最终归结为以下一种或另一种形式:

FetchNextRow
while (not EnfOfResults)
{
  ProcessRow;
  FetchNextRow;
}

这意味着什么,实际上,它可能是foreach row in IQueryableSqlDataReader.Read()。但基本思想是相同的,客户端从结果中获取行,处理它们,然后获取更多行。如果客户端代码在ProcessRow 中执行了任何操作 阻塞,那么客户端代码将不会到达它再次获取下一行的点,因此最终将触发 TCP 流控制,这反过来将导致 SQL Server 暂停查询(因为它没有地方可以写入结果)。就 TCP 而言,您无法做任何事情来改善这一点。增加窗口大小实际上会使事情变得更糟,因为现在所有以前在源 (DB) 中被抑制的结果都将被创建并且必须存储在某个地方,这最终意味着将实时内存分配给存储,并且可能会使事情变得更糟比现在更糟。

如果我现在处于你的位置,我会专注于确定ProcessRow 阻塞发生在哪里。我提出的一个假设是,该处理将是一个 MVC 视图写入响应缓冲区并被 TCP 流控制依次阻止,这是由于用户代理未使用 HTTP 响应(例如,Ajax 调用已完成但浏览器未运行)使用响应的完成代码,因为主线程正在忙于其他事情)。与往常一样,最好的方法是有条不紊地进行测量。一些可能的工具:

【讨论】:

  • RE 1) 为什么选择 TCP 流量控制?我看到很多“零窗口消息”从 Web 服务器传输到 SQL 服务器(每个 Web 服务器每分钟大约 500 条)。我还经常看到缓冲区徘徊在 ~200-300 字节左右。所以我猜这是时间尺度,窗口接近零的频率。然而,当它达到零时,窗口更新很快就会消失(2-3MS)。我现在要去看看等待DMV ...
  • 更新了我的问题以包含 DMV 查询。 ASYNC_NETWORK_IO 出现了,但如果它高于应有的值,我有点无知。将翻阅我的“SQL Server 2008 Internals”新副本,看看我是否无法了解如何深入了解导致此问题的查询。
  • 最大等待时间 16707 毫秒意味着至少有一项任务必须等待 +16 秒才能释放网络,这将证实您的初步结论。但这也表明应用程序做了一个 DB 请求,然后在长达 16 秒的时间内没有费心去读取结果(空闲缓冲区)。鉴于这是 ASP,需要调查的一件事是用户代理拥塞是否会阻塞您的 IIS/ASP 缓冲区,这会导致您的 ASP 线程等待输出缓冲区,进而使其忽略 DB 请求。
  • 换句话说,用户浏览SO,互联网拥塞或浏览器卡在JavaScript中导致它无法读取HTTP响应,从而导致一直到数据库的拥塞(表现为TCP流量控制)。在这种情况下,查看 TCP 参数或 .Net ADO SqlClient 会发现错误的树。即使您设法从数据库中提取更多数据并释放该管道,如果您无法通过 HTTP 将其推送到另一个管道到用户代理,那么数据将在某处累积,你会因为内存耗尽而遇到问题。
  • 这对我来说很有意义,但我不确定我是否理解它是否适​​合。原因是负载均衡器将向 Web 服务器发出所有 HTTP 请求并读取我认为的响应。 (事实上​​,如果我没记错的话,它会在自己和客户端之间保持持久连接,但不会在自己和服务器之间保持连接)。即使同时进行客户端中止和服务器端中止,对于单个服务器,我在一小时内也只能看到大约 50 条(相对于服务器每分钟看到 200 条左右的零窗口消息)
猜你喜欢
  • 2013-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多