3

(来自服务器故障的交叉发帖,我没有得到任何牵引力):我一直试图追查导致 Web 请求由于意外错误而终止后 ASP .NET 会话状态保持锁定状态的根本原因。我们使用 SQL Server 会话状态提供程序进行会话,因为我们在 Web 场中有多个服务器。这个问题首先表现为许多请求无缘无故地卡在其生命周期的“AcquireRequestState”事件中。我能够在 SQL Server 的会话状态数据库中找到这些请求的相应条目,这些条目都被锁定(列 Locked = 1)。我还能够将这些请求与 IIS 日志中的条目相关联,HTTP 状态代码为 500(子状态为 0)。这些发现让我相信,在某些情况下,

我在 IIS 中为有问题的网站启用了失败的请求跟踪,状态代码为 500,所有可用的提供程序都选择了每个提供程序,每个提供程序的详细程度都设置为“详细”。我已经收集了几个导致永久锁定 ASP .NET 会话的失败跟踪。它们都具有相同的特征:

  • 它们都是浏览器发布要处理/保存的数据的“POST”请求。
  • 它们都有事件表明在 REQUEST_ACQUIRE_STATE 事件期间调用了“会话”模块。此时,请求会将会话状态数据库中的行标记为“锁定”。这是正常的,也是意料之中的。
  • 它们都有 GENERAL_READ_ENTITY_START、GENERAL_READ_ENTITY_END 和 GENERAL_REQUEST_ENTITY 条目,这些条目似乎正在读取作为请求的一部分发布到服务器的数据。这似乎是一种缓冲操作,因为这些事件会一遍又一遍地重复,每个事件都会读取发布数据的某个子集。
  • 在“读取实体”相关事件期间的某个时间点会发生错误。有些有错误代码“不正确的功能。(0x80070001)”和其他有“由于线程退出或应用程序请求,I/O 操作已中止。(0x800703e3)”。
  • 一旦遇到错误,它们都会直接跳转到 END_REQUEST 事件。

这里的问题是,在正常情况下,应该有一个 RELEASE_REQUEST_STATE 事件允许 Session 模块释放它在会话上的锁。在这种情况下将跳过此事件。可以肯定的是,我还为“200”状态代码启用了失败的请求跟踪,并生成了几个成功请求的跟踪,这些跟踪确实具有由 Session 模块处理的 RELEASE_REQUEST_STATE 事件。

一位同事指出,您还可以通过调用 HttpContext.Current.ApplicationInstance.CompleteRequest() 使请求直接跳到“END_REQUEST”事件。我对此进行了测试,发现在发布请求期间使用此方法会创建一个非常类似于我在此问题发生时捕获的跟踪,但会话仍然会得到正确清理。这导致我在存储会话的 SQL Server 数据库上运行 SQL Profiler,以跟踪对存储过程的所有调用。当我们由于调用 CompleteRequest() 而直接跳到 END_REQUEST 时,会按预期进行调用以更新会话状态(并释放锁)。当我们在 GENERAL_REQUEST_ENTITY 期间由于错误而跳到 END_REQUEST 时,永远不会调用更新或释放会话状态的锁定。

我此时的理论是某种网络问题导致“功能不正确”和“I/O 操作因线程退出或应用程序请求而中止”错误,但我不明白为什么这看起来导致请求处理跳过释放会话状态的锁定。如果请求通过 REQUEST_ACQUIRE_STATE 似乎它也应该在请求结束时的某个时刻释放锁。我不愿意说这是 IIS 或 ASP .NET 中的错误,但在这一点上对我来说确实是这样。

是否存在任何已知的错误会导致会话状态锁不被释放的情况?

4

1 回答 1

1

事实证明,这与以下问题有关:ManagedPipelineHandler for an AJAX POST crash if an IE9 user navigation away from a page while that call is in progress

在该问题的已接受答案中指定的解决方法确实有效,但微软还发布了一个修补程序(在撰写本文时尚未公开提供),该修补程序修补会话处理逻辑以避免一起出现问题。

于 2013-11-15T14:18:38.907 回答