我有一个 .NET 6 Web 应用程序,在使用 Kestrel 时间歇性崩溃:
System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.
at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketAwaitableEventArgs.<GetResult>g__ThrowSocketException|5_0(SocketError e)
at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketAwaitableEventArgs.GetResult(Int16 token)
at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketConnection.DoReceive()
at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
at System.IO.Pipelines.Pipe.GetReadAsyncResult()
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequestsAsync[TContext](IHttpApplication`1 application)
at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketAwaitableEventArgs.<GetResult>g__ThrowSocketException|5_0(SocketError e)
at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketAwaitableEventArgs.GetResult(Int16 token)
at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketConnection.DoReceive()
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequestsAsync[TContext](IHttpApplication`1 application)
Microsoft.AspNetCore.Server.Kestrel: Warning: Connection processing ended abnormally.
我无法可靠地导致它发生,但它最终总是会发生,通常是在跑步 5-20 分钟后。网络应用程序完全停止,这是我们可以从任何日志记录中得到的最后一条消息。
这看起来像是某种套接字连接错误,但它发生在本地计算机上,它发生在附加的 VSCode 或 VS2022 调试器上。
整个堆栈都指向 Microsoft 代码,其中没有任何部分指向我们应用程序中的代码。
知道从哪里开始解决这个问题吗?可能是什么原因造成的?
造成这种情况的原因是 .NET 中埋藏着一把枪,对于从 .NET Core 升级到现代 .NET 的任何人来说
我们发现
dotnet.exe
和 w3wp.exe
正在创建数百个 IPv4 环回连接。最终他们用完了,我们就会遭遇这次事故。
Kestrel 的早期版本不在 IIS 中运行 - 相反,IIS 会运行代理并将连接传递到 Kestrel(更多内容请参阅此 answer)。该代理有一个相当严重的错误 - 取消令牌会导致 IIS 关闭连接并继续,但 IIS 不会告诉 Kestrel,它只会继续运行。
每次发生取消令牌时,
w3wp.exe
都会取消环回连接,但dotnet.exe
将继续执行其正在处理的任何缓慢的操作。与此同时,对于我们的用户来说,事情会变得更慢(更多的是排队),因此他们会离开,取消另一个请求并使队列变得更糟。
但是我们现在使用的是.NET7,它应该正在运行,对吧?
首先,我们在启动时仍然使用
WebHost.CreateDefaultBuilder
(.NET Core 方法)而不是 WebApplication.CreateBuilder
(自 .NET6 以来的新方法) - 旧的 Core 方法默认为 Kestrel 在进程外运行。
所以我们修复了这个问题并且它仍然发生了。
我们错过了
web.config
这里也有一个设置:
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
这导致 Kestrel 仍然会在进程外运行,并且每当发生太多导航取消时就会崩溃。
最终修复是:
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
一旦我们完成了所有这些,它就终于被修复并不再发生了。如果您发现自己遇到同样的问题,请调试您的代码并检查当前进程名称 (
Process.GetCurrentProcess().ProcessName
) - 如果它是 w3wp.exe
很好,那么您正在 IIS 中运行,但如果您使用的是 IIS 并且您会得到 dotnet.exe
相反,这意味着它会退回到进程外模式,并且(如果您使用取消令牌)您可能会看到与连接池相关的相同崩溃。