【问题标题】:Intermittent crash of w3wp.exe with ThreadAbortException after .NET 4.6 upgrade.NET 4.6 升级后 w3wp.exe 间歇性崩溃并出现 ThreadAbortException
【发布时间】:2016-01-05 05:17:13
【问题描述】:

在过去的几天里,我们看到为我们公司网站的主应用程序池提供服务的 w3wp.exe 工作进程间歇性崩溃。有时崩溃是孤立的,IIS 能够成功地重新启动工作进程。但如果 5 分钟内发生超过 5 次崩溃,IIS 快速故障保护就会启动并停止应用程序池。以下是崩溃前应用程序事件日志中的示例条目:

An unhandled exception occurred and the process was terminated.
Application ID: /LM/W3SVC/2/ROOT
Process ID: 3640
Exception: System.Threading.ThreadAbortException
Message: Thread was being aborted.
StackTrace:    at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)

在由于 ThreadAbortException 导致的崩溃之后,立即记录了一个更严重的事件:

Faulting application name: w3wp.exe, version: 8.0.9200.16384, time stamp: 0x5010885f
Faulting module name: KERNELBASE.dll, version: 6.2.9200.17366, time stamp: 0x554d16f6
Exception code: 0xe0434352
Fault offset: 0x00010192
Faulting process id: 0xe38
Faulting application start time: 0x01d100dc662652d6
Faulting application path: C:\Windows\SysWOW64\inetsrv\w3wp.exe
Faulting module path: C:\Windows\SYSTEM32\KERNELBASE.dll
Report Id: db5b0d5b-6cd0-11e5-9418-005056900458
Faulting package full name: 
Faulting package-relative application ID: 

现在,ThreadAbortException 永远不会导致 w3wp.exe 崩溃,因为每次执行标准 Response.Redirect() 时都会抛出它。 MSDN confirms this,我还用simple test 确认了这一点。但是,最近至少有一个人在类似的环境中看到了类似的崩溃:Thread.Abort in ASP.NET app causes w3wp.exe to crash。 (但这可能是一个不相关的问题。)

我们的环境:

  • 带有购物车和合作伙伴网络服务的企业网站;针对 .NET 4.5。 (超过 900,000 行自定义代码,包括业务逻辑 DLL 和内部库。)
  • 使用 Windows NLB 的负载平衡池中的 2 个 VMWare Web 服务器
  • IIS 8.0 / Windows 2012 Server Standard / .NET 4.6.00081
  • 应用程序池在 32 位模式下运行,因为我们必须支持少数调用旧版 VB6 DLL 的经典 ASP 页面。

背景:

在崩溃开始前几天,我们升级到了 .NET 4.6。我们启用了新的 RyuJIT(默认设置),并安装了所有更新以解决此处描述的关键编译器问题:http://blogs.msdn.com/b/dotnet/archive/2015/07/28/ryujit-bug-advisory-in-the-net-framework-4-6.aspx

我们还部署了新版本的 Web 代码(我们每周都会这样做几次)。自然,我们仔细检查了代码更改是否存在任何潜在的崩溃漏洞,但我们的任何更改似乎都不会受到无限循环、递归堆栈溢出或高内存使用率的影响——当 w3wp.exe 因未处理的异常而崩溃时,这些都是正常的罪魁祸首。

有时崩溃会在几分钟内影响到另一台网络服务器,但有时只有一台网络服务器受到影响。

我尝试过的事情:

  • 重新启动服务器并安装所有 Windows 更新。
  • 分析 IIS 日志以查看在崩溃前是否有任何可疑/错误请求进入。我找不到任何模式——所有请求 看起来很正常。
  • 为 w3wp.exe 启用自动崩溃小型转储(如 https://msdn.microsoft.com/en-us/library/bb787181.aspx 所述)并使用 WinDbg 对其进行分析。不幸的是,CLR“感兴趣的堆栈跟踪”没有显示任何有用的信息,只是几个与我们的代码无关的空 GC 帧:
> 0:026> !clrstack
> OS Thread Id: 0x1ff0 (26)
> Child SP       IP Call Site
> 2321f96c 771bdf8c [GCFrame: 2321f96c]
> 2321f9a4 771bdf8c [GCFrame: 2321f9a4]

有什么想法吗?

更新:

我们已在我们的 Web 服务器上回滚 .NET 4.6 和最近的 Windows 更新。我们已经对此进行了 2 或 3 天的监控,具体取决于服务器回滚的时间,并且在每种情况下,尽管维护相同的应用程序代码,但随后的崩溃都为零。 这非常明确地证明 .NET 4.6 或其他 Windows 更新导致了间歇性崩溃,不是我们的代码,因为 w3wp.exe 之前每天会崩溃几次。

我们现在正试图向 Microsoft 支持证明这一点,但这是一场艰苦的战斗,因为问题是随机的、间歇性的,而且我们无法可靠地重现它。 (他们提供了dump analysis,但它似乎是一个红鲱鱼。)我们也在分组重新应用更新并等待几天观察崩溃,以努力隔离错误的更新。显然这是一个乏味的过程。

更新 #2:

我们现在重新应用了在故障排除中删除的所有 pre-.NET 4.6 Windows 更新,并且服务器已经运行了几天而没有崩溃。唯一需要重新应用的是 .NET 4.6 和它自己的更新,但我的管理层不愿意安装可能会导致生产崩溃的东西,这是可以理解的。因此,我将继续与 MS 合作分析不同的故障转储以查明问题。

【问题讨论】:

  • 您是否在站点代码中手动启动任何线程?
  • @mason 是的,我们的代码多年来一直在这样做以并行化某些中等长度的 API 调用。但从来都不是问题,最近那部分代码也没变过。
  • 任何与 HTTP 请求无关的线程中的异常都会导致进程中断。我敢打赌它与 .NET 4.6 无关,这可能是巧合。你不应该启动自己的线程。根据任务的持续时间,您可能能够使用基于任务的异步编程,或者转向在后台运行该代码的其他方法。请参阅 Phil HaackScott Hanselman 的博文。
  • @mason 总的来说,我同意我们不应该启动自己的线程。但是我们有一个用例,我们希望同时调用多个不同的 API 并严格控制使用的线程数(每个合作伙伴一个,通常一次只有几十个)和持续时间(大约 30 秒)。因此,对于这一点,我们喜欢手动线程为我们提供的精细控制,而不是像任务这样的线程池支持的实现。无论如何,如果我们的一个用户线程被手动中止,崩溃转储堆栈跟踪不会显示吗?我想会尝试重现这种情况。
  • 你试过禁用整机的RyuJIT吗?我们遇到了有趣的问题。

标签: asp.net iis crash w3wp .net-4.6


【解决方案1】:

您没有显示任何代码,但证据表明这是您的应用程序代码的问题,而不是 .NET 4.6 或 ThreadAbortException 的问题。

这里的基本故障排除步骤:您说有代码更改和环境更改;所以排除其中一个。

  • 在安装了 .NET 4.5 的 VM 上测试应用程序。如果您没有收到错误,可能是 .NET 4.6 的原因。

  • 在同一台服务器上测试您的应用程序的旧版本。如果没有发现问题,可能是代码更改的原因。

  • 在安装了 VS.NET 的机器上测试应用程序,附加到 w3wp.exe 进程,然后调试它(工具 > 附加到进程)。抓住ThreadAbortException 并追踪它。

  • 如果您还没有,您应该记录您的w3wp.exe 进程停止的事件。虽然这显然不会处理所有异常。谷歌这个,但是this guy describes a solution that I also use

  • 如果您还没有,请在 Global 中定义一个 Application_Error 处理程序以记录异常。 Microsoft demonstrates this。创建一个System.Web.Configuration 选项,您可以在web.config 文件中切换该选项以启用不同级别的日志记录,例如写入本地文件和写入Windows 事件日志。你也可以安装一个日志处理工具,比如Elmah

  • 创建一个准系统简单的 Web 应用程序并测试 Response.Redirect 以验证它是否使用 .NET 4.6 使 w3wp.exe(工作进程)崩溃。我这样做了,但没有,所以我怀疑你的代码。或者可能是奇怪的服务器/补丁级别紧急问题..这些步骤应该可以帮助您查明它。

旁注:即使它不应该影响应用程序进程,我还是建议修复Response.Redirect() 问题。我们最近在一个企业应用程序中这样做了,是的,这是一个广泛的变化,但我们不再得到 TAE 例外。修复很简单:只需调用Response.Redirect(false);,然后确保在调用该函数后没有代码将运行(例如调用return)。 This post explains

【讨论】:

  • 我们昨天在我们的一个 Web 服务器上恢复到 .NET 4.5(但仍在使用我们的最新代码。)到目前为止,该服务器还没有崩溃——这强烈表明 .NET 4.6 是罪魁祸首,但我不能肯定地说,直到它没有崩溃的时间更长,因为崩溃是随机的,不可能按需重现。我们已向 Microsoft 支持人员提供了故障转储,但到目前为止,他们的分析似乎无济于事。 Response.Redirect() 可能与我们的问题无关,因为转储中的 CLR 堆栈跟踪指向控制渲染代码中的无限循环。
  • 您的某个应用程序中有递归函数吗?几个月前我遇到了同样的问题,发现实际问题出在我自己的代码而不是服务器上(即意外情况导致无限循环)。 nothingisnecessary 的回答似乎是正确的。
  • 我们的 Web 应用程序,包括业务逻辑 DLL 和内部库,代码超过 900,000 行。它确实包含用于某些特定任务的少量递归代码,但该代码经过充分测试,最近没有更改,并且不会在每个 Web 请求上随机运行。
  • 因此,在所有服务器上回滚 .NET 4.6(以及一系列不相关的 Windows 更新)后,崩溃率为零。服务器已回滚 2 到 3 天。我们的应用程序代码没有改变。 这非常明确地证明 .NET 4.6 或其他 Windows 更新导致间歇性崩溃,而不是我们的代码,因为 w3wp.exe 之前每天崩溃几次。 我们现在正试图证明这一点到 Microsoft 支持,但这是一场艰苦的战斗,因为问题是随机的、间歇性的,而且我们无法可靠地重现它。
  • 感谢您提供详细信息。同意您的证据可能表明该环境组合(.NET 4.6 和 Server 2012)存在紧急问题。我们还希望将 64 位 Web 应用程序迁移到 RyuJIT 和 4.6,因此我想事先了解此问题的原因。但是,我们在测试环境中没有注意到这个问题,所以我想知道引入更多负载是否会触发它。我会及时通知你。
【解决方案2】:

@Jordan Rieger,这个错误应该在 .NET 4.6.1 中修复 您能否确认问题是否在新框架中得到修复?或者如果它仍然存在?谢谢。

【讨论】:

  • 看来.NET 4.6.1 确实解决了这个问题,因为我们已经安装了几个星期而没有遇到这个问题。从 .NET 4.6 回滚到 4.5 也为我们暂时修复了它,但我很高兴现在使用最新的稳定版本。
【解决方案3】:

4.6 不稳定 (http://nickcraver.com/blog/2015/07/27/why-you-should-wait-on-dotnet-46/),如果可能,请恢复到 4.5.x。

【讨论】:

  • 我们正在考虑恢复到 4.5.x 或禁用 RyuJIT,但根据微软的说法,他们已经解决了 Nick Craver 和 Marc Gravel 发现的问题,正如我在问题中提到的那样,我们有已安装更新:blogs.msdn.com/b/dotnet/archive/2015/07/28/….
  • 已解决,但目前没有证据表明 4.6 是稳定的,例如没有其他问题。
猜你喜欢
  • 2011-06-07
  • 1970-01-01
  • 2015-05-21
  • 2013-06-14
  • 2012-12-31
  • 2015-11-22
  • 1970-01-01
  • 2017-12-28
相关资源
最近更新 更多