Compartilhar via

排查Azure App Service中的间歇性出站连接错误

本文可帮助你排查间歇性连接错误以及 Azure App Service 中相关的性能问题。 它提供有关源网络地址转换 (SNAT) 端口耗尽的详细信息及其故障排除方法。 如果在阅读本文的任何时候需要更多帮助,请联系 Azure 社区支持 的专家。 或者,可以提交Azure support事件。 转到 Azure 支持 并选择 提交支持请求

症状

托管在Azure App service上的应用程序和函数可能会显示以下一个或多个问题:

  • 服务计划中的所有或部分实例的响应速度缓慢。
  • 间歇性 5xx 错误或“错误的网关”错误
  • 超时错误消息。
  • 无法连接到外部终结点(如 SQLDB、Service Fabric 或其他应用服务)。

原因

出现间歇性连接问题的主要原因是在建立新的出站连接时遇到了限制。 可能遇到的限制包括:

  • TCP 连接:可以建立的出站连接数有限制。 对出站连接的限制与使用的工作器大小有关。
  • SNAT 端口:Azure 中的出站连接描述了 SNAT 端口限制以及这些限制如何影响出站连接。 Azure使用源网络地址转换(SNAT)和负载均衡器(不向客户公开)来与公共 IP 地址通信。 Azure App service上的每个实例最初都给定预先分配的 128 SNAT 端口数。 SNAT 端口限制会影响与同一地址和端口组合的连接。 如果应用与混合的地址/端口组合建立了连接,则不会用尽 SNAT 端口。 重复调用同一个地址/端口组合时,会用尽 SNAT 端口。 发布端口后,可根据需要重复使用该端口。 Azure 网络负载均衡器需要等待四分钟后才会从关闭的连接中回收 SNAT 端口。

当应用程序或功能快速打开新连接时,它们可以快速耗尽其 128 个端口的预分配配额。 然后,应用程序或功能会一直受到阻止,直到通过动态分配更多的 SNAT 端口或者通过重复使用回收的 SNAT 端口提供了新的 SNAT 端口为止。 如果应用耗尽了 SNAT 端口,将出现间歇性的出站连接问题。

避免问题

有一些解决方案可以避免 SNAT 端口限制。 它们包括:

  • 连接池:利用连接池,可以避免为对同一地址和端口的调用而打开新的网络连接。
  • 服务终结点:对使用服务终结点保护的服务没有 SNAT 端口限制。
  • 专用终结点:对使用专用终结点保护的服务没有 SNAT 端口限制。
  • NAT 网关:使用 NAT 网关时,你会得到 64,000 个出站 SNAT 端口,通过该网关发送流量的资源可以使用这些端口。

为了避免 SNAT 端口问题,请避免对同一主机和端口反复创建新连接。 连接池是解决该问题更简单明了的方法之一。

如果您的目标是支持服务终结点的 Azure 服务,则可以通过使用区域虚拟网络集成和服务终结点或专用终结点来避免 SNAT 端口耗尽问题。 使用区域虚拟网络集成并在集成子网上放置服务终结点时,发往这些服务的出站应用流量不会有 SNAT 出站端口限制。 同样,如果使用区域虚拟网络集成和私有端点,那么对于该目标不会存在任何出站 SNAT 端口的问题。

如果目标是 Azure 外部的外部终结点,使用 NAT 网关提供 64k 个出站 SNAT 端口。 它还提供了一个专用的出站地址,您不用与任何人共享。

如果可能,请对代码进行改进,以使用连接池并避免整个情况。 更改代码并不总是能迅速进行,以致无法及时缓解这种情况。 如果无法及时更改代码,可以利用其他解决方案。 该问题的最佳解决方法是尽量结合使用所有解决方案。 尝试对 Azure 服务使用服务终结点和专用终结点,并为其他部分使用 NAT 网关。

若要详细了解缓解 SNAT 端口耗尽的策略,请参阅 将 SNAT 用于出站连接。 在这些策略中,以下策略适用于托管在 Azure App service 上的应用和函数。

使用连接池

以下文章介绍了如何通过不同的解决方案堆栈实现连接池。

Node

默认情况下,Node.js 的连接不会保持活动状态。

HTTP 保持活动状态

Java

Java Database Connectivity (JDBC) 连接池

HTTP 连接池

PHP

尽管 PHP 不支持连接池,但你可以尝试使用到后端服务器的持久数据库连接。

Python

HTTP 连接池

  • Requests 模块中默认启用“保持活动状态”和 HTTP 连接池。
  • Urllib3

复用连接

有关在 Azure Functions 中管理连接的更多指针和示例,请参阅 在 Azure Functions 中管理连接

使用主动性较低的重试逻辑

有关更多指南和示例,请参阅 Retry 模式

使用“保持活动状态”重置出站空闲超时

若要为 Node.js 应用实现“保持活动状态”,请参阅我的 Node 应用程序正在发出过多的出站调用

针对App Service的更多指南

  • 将 App Service 计划横向扩展,以增加更多实例。 有关缩放的详细信息,请参阅 scale a app in Azure App Service。 在应用服务计划中,每个工作器实例都分配了一定数量的 SNAT 端口。 如果将用量分散在多个实例之间,可能会使每个实例的 SNAT 端口用量不超过每个独特远程终结点的建议出站连接数限制(100 个)。
  • 请考虑迁移到 App Service Environment (ASE),这将为您分配一个单一的出站 IP 地址,并且连接和 SNAT 端口的限制也更高。 在 ASE 中,每个实例的 SNAT 端口数基于 Azure load balancer 预分配表。 例如,具有 1-50 个辅助角色实例的 ASE 每个实例有 1,024 个预分配端口,而具有 51-100 个辅助角色实例的 ASE 每个实例有 512 个预分配端口。

避免超过出站 TCP 限制要更容易一些,因为这些限制是根据工作器的大小设置的。 可以在 Sandbox 中查看跨 VM 数值限制 - TCP 连接数限制

限制名称 描述 小型 (A1) 中型 (A2) 大型 (A3) 隔离层 (ASE)
连接 整个 VM 的连接数 1920 3968 8064 16,000

为避免出站 TCP 限制,可以增加工作进程的大小或进行水平扩展。

故障排除帮助

了解两种类型的出站连接限制以及应用的作用后,应该就可以更轻松地进行故障排除。 如果你知道你的应用对同一storage帐户进行了多次调用,则可能怀疑 SNAT 限制。 如果应用完全通过 Internet 向终结点发出大量的调用,可以怀疑达到了虚拟机限制。

如果不知道应用程序行为足以快速确定原因,App Service中提供了一些工具和技术来帮助确定这一决定。

查找 SNAT 端口分配信息

  1. 若要访问 App Service 诊断,请导航到 Azure 门户中的 App Service 网站应用程序或 App Service Environment。 在边栏菜单中,选择“ 诊断”并解决问题
  2. 选择 “可用性和性能 ”类别。
  3. 在该类别下的可用磁贴列表中,选择“SNAT 端口耗尽”磁贴。 做法是将其保持在 128 以下。 如果确实需要,仍可以开具支持票证,支持工程师会从后端为你提取指标。

由于 SNAT 端口使用情况不能作为指标提供,因此无法基于 SNAT 端口使用情况自动缩放,也不能根据 SNAT 端口分配指标配置自动缩放。

TCP 连接和 SNAT 端口

TCP 连接和 SNAT 端口并不直接相关。 在任何应用服务应用的Diagnose 与解决问题管理页中均包含有TCP连接使用情况检测器。 搜索短语“TCP 连接”即可找到它

  • SNAT 端口仅用于外部网络流,而 TCP 连接总数包括本地环回连接。
  • 如果协议、IP 地址或端口中的流不同,则一个 SNAT 端口可由不同的流共享。 TCP 连接指标统计每个 TCP 连接。
  • TCP 连接限制在工作实例级别发生。 Azure网络出站负载均衡不使用 TCP 连接指标来限制 SNAT 端口。
  • TCP 连接限制在 Sandbox 跨 VM 数值限制 - TCP 连接中介绍。
  • 从Azure App Service源端口添加新的出站 TCP 会话时,现有 TCP 会话会失败。 你可以使用单个 IP 或重新配置后端池成员以避免冲突。
限制名称 描述 小型 (A1) 中型 (A2) 大型 (A3) 隔离层 (ASE)
连接 整个 VM 的连接数 1920 3968 8064 16,000

WebJobs 和数据库连接

如果 SNAT 端口耗尽,导致 WebJobs 无法连接到 SQL 数据库,则不会有任何指标显示每个 Web 应用程序进程打开的连接数。 若要查找有问题的 Web 作业,请将多个 Web 作业移出另一个App Service计划,以查看情况是否有所改善,或者某个计划中是否存在问题。 重复此过程,直到找出有问题的 WebJob。