从 Azure 中托管的 ASP.NET Core 5.0 MVC 站点调用 API/服务的间歇性套接字异常

Posted

技术标签:

【中文标题】从 Azure 中托管的 ASP.NET Core 5.0 MVC 站点调用 API/服务的间歇性套接字异常【英文标题】:Intermittent Socket Exceptions calling API / Services from ASP.NET Core 5.0 MVC site hosted in Azure 【发布时间】:2021-06-30 13:40:02 【问题描述】:

Application Insights 中的错误消息:

连接尝试失败,因为连接方在一段时间后没有正确响应,或者连接失败,因为连接的主机没有响应。 (OurApiUrlAddress:443) 连接尝试失败,因为连接的一方在一段时间后没有正确响应,或者连接失败,因为连接的主机没有响应。

始终是 21 秒的 TCP 超时,我知道这是一个非常普遍的错误,但此错误的原因并不总是相同,我一直在阅读所有关于此的线程。几个月来我们一直在调查这个问题,但没有成功,我们也在与 Azure 团队联系。

重要提示:这个用 RUBY 编写的同一个站点过去使用同一个 API 没有任何问题,该 API 是响应式的,并且从其他站点调用它没有任何问题,但是这个特定站点已被迁移从 RUBY 到 .NET,同时该站点托管在 AZURE 中,这是 2 大变化。当站点(记住它托管在 Azure 中)调用我们公司托管的 API / 服务时会发生这种情况,当站点调用托管在其他地方的服务时不会发生这种情况,这让我们认为问题可能与公司基础设施有关但不能仅此而已,这必须以某种方式与 .NET 和 AZURE 相关,因为这些 API 和服务可以完美地响应来自我们网络中托管的其他站点的调用,并且它们在该站点的 ruby​​ 版本中运行良好。当从公司网络外部在浏览器中调用时,这些 API 和服务不会引发此错误。

服务/api 位于防火墙后面,但端口配置完美(没有任何其他流量应用或设备在使用)。

此错误似乎与端口耗尽或 SNAT 相关,因为有时只有 1 个开发人员在 DEV 环境中工作并且他收到此套接字异常错误。

只是为了说明我们在生产中每天会收到大约 250 个套接字异常,而这只是所有调用的一小部分,所以有时会发生这种情况。

我们知道创建多个实例时众所周知的 HttpClient 问题,因此我们决定使用单例方法确保每个 API/服务只有 1 个实例,正如我将在此处展示的那样,这是提供更多套接字异常的调用:

StartUp 类/文件中:

services.AddSingleton<IUploadApi>(new UploadApi(new HttpClient()  BaseAddress = new Uri(appSettings.Endpoints.UploadServicesUrl) ));

appsettings.json的一部分:

"Endpoints": 
    "UploadServicesUrl": "https://ourApiUrlAddress"
,

UploadApi.cs

public interface IUploadApi

    Task<UploadArtworkViewModel.UploadConfigurationData> GetUploadConfiguration();


public class UploadApi : IUploadApi

    private readonly HttpClient httpClient;

    public UploadApi(HttpClient client)
    
        httpClient = client;
    

    public async Task<UploadArtworkViewModel.UploadConfigurationData> GetUploadConfiguration()
    
        var response = await httpClient.GetAsync("api/GetUploadConfiguration").ConfigureAwait(false);
        var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

        return JsonConvert.DeserializeObject<UploadArtworkViewModel.UploadConfigurationData>(json);
    

从控制器调用:

model.UploadConfiguration = await UploadApi.GetUploadConfiguration().ConfigureAwait(false);

欢迎任何关于要测试的东西或要看的地方的想法,显然我无法重现这个。我们知道总是有 21 秒的超时,这是一个 TCP 超时,但这并没有多大帮助。可能由于某种原因连接断开或 Azure 在访问公司网络时(有时)出现问题。如果需要,我可以从应用程序洞察中发布更多信息,但我没有看到任何关于该错误的特别信息。

编辑 - 更多信息:当从这个 MVC 站点控制器调用任何 API 或服务时会发生这种情况,因此当站点服务器尝试访问时,问题会偶尔出现(仍然像每天 300 次)一个 API 或服务,这让我相信它与公司的基础设施有关,但仍然不知道它可能是什么。

【问题讨论】:

您可以尝试使用 HttpClientFactory 而不是 HttpClient Singleton。机会很小,但至少它会每隔一段时间回收一次实例。 感谢您的回答!好的,我已经准备好我的代码来测试这个,这也可以轻松实现重试策略。我看看我明天是否可以在产品上测试这个。我希望我明天有关于结果的信息。 有人告诉我这种方法以前使用过,结果相同,最终改为单例方法,因为它有更好的超时结果:( 只是为了确认 HttpClientFactory 方法已经过测试并且发生了同样的情况,我们得到了套接字异常。关于重试策略,我们现在正在尝试修复套接字异常问题,因此我们暂时不会添加重试以“隐藏”它。 是您的应用服务计划窗口吗? 【参考方案1】:

来自 asp.net 的怪物:

"应用程序已退出,但仍有一堆 连接打开”

"他们处于 TIME_WAIT 状态,这意味着连接有 一侧(我们的)已关闭,但我们仍在等待是否有 额外的数据包进入它,因为它们可能已被延迟 在某处的网络上。”

即使您使用的是单例 HttpClient,似乎有些连接正在等待其他包,这会导致套接字耗尽。

解决方案是更改代码并使用 HttpClientFactory 或HttpClientFacotoryLite。使用 HttpClientFactory 的原因是生成 HttpClient 实例,这些实例可以从套接字处理程序池中重新使用 Socket 处理程序。处理程序会定期回收以处理 DNS 更改。总之,在使用 HttpClientFactory 时,HttpClient 将工作委托给 SocketClientHandler。

【讨论】:

mmm HttpClientFacotory 是我们在实现 Singleton 之前使用的,我们遇到了同样的问题。我们测试了不同的方法,结果相同。 如果即使使用 HttpClientFactory 你也面临这个问题,这意味着当前的应用服务计划不足以满足你的 http 请求。【参考方案2】:

在与 Azure 团队合作一段时间后,我们终于解决了这个问题,这是一个网关问题,解决方案是应用 NAT/Vnet 集成。这是我们为修复它所做的: https://docs.microsoft.com/en-us/azure/app-service/networking/nat-gateway-integration

【讨论】:

以上是关于从 Azure 中托管的 ASP.NET Core 5.0 MVC 站点调用 API/服务的间歇性套接字异常的主要内容,如果未能解决你的问题,请参考以下文章

在 Chrome 中托管在 Azure 中的 ASP.NET Core Web 应用程序上的异常 HTTP 响应

ASP.NET Core API - 在 Azure 应用服务上获取 404,但在 Localhost 上工作正常

如何在 ASP.net Core WebAPI 中启用 CORS

从托管为 Azure Web App 的 ASP.NET 5 应用程序记录日志

如何为 ASP.NET Core 应用配置 Azure 应用服务日志记录提供程序?

Azure AD 限制整个 ASP.NET Core API