排查 Azure 应用服务中的间歇性出站连接错误
本文帮助你排查 Azure 应用服务中的间歇性连接错误和相关性能问题。 本主题将提供有关源地址网络转换 (SNAT) 端口耗尽的详细信息及其故障排除方法。 如果对本文中的任何观点存在疑问,请通过 Azure 支持联系 Azure 专家。 或者,提交 Azure 支持事件。 转到 Azure 支持站点。
症状
托管在 Azure 应用服务中的应用程序和功能可能会出现以下一种或多种症状:
- 服务计划中的所有或部分实例的响应速度缓慢。
- 间歇性 5xx 错误或“错误的网关”错误
- 超时错误消息
- 无法连接到外部终结点(例如 SQLDB、Service Fabric、其他应用服务等)
原因
出现间歇性连接问题的主要原因是在建立新的出站连接时遇到了限制。 可能遇到的限制包括:
- TCP 连接数:可以建立的出站连接数有限制。 对出站连接的限制与使用的工作器大小有关。
- SNAT 端口数:Azure 中的出站连接介绍了 SNAT 端口限制以及它们对出站连接的影响。 Azure 使用源网络地址转换 (SNAT) 和负载均衡器(位向客户公开)与公共 IP 地址通信。 最初为 Azure 应用服务中的每个实例预分配了 128 个 SNAT 端口。 SNAT 端口限制会影响与同一个地址/端口组合打开的连接数。 如果应用与混合的地址/端口组合建立了连接,则不会用尽 SNAT 端口。 重复调用同一个地址/端口组合时,会用尽 SNAT 端口。 释放某个端口以后,即可根据需要重复使用该端口。 只有在等待 4 分钟后,Azure 网络负载均衡器才会从关闭的连接回收 SNAT 端口。
当应用程序或功能快速打开新的连接时,它们可能很快就会耗尽预分配的配额(128 个端口)。 然后,应用程序或功能会一直受到阻止,直到通过动态分配更多的 SNAT 端口或者通过重复使用回收的 SNAT 端口提供了新的 SNAT 端口为止。 如果应用用完了 SNAT 端口,则会出现间歇性的出站连接问题。
避免问题
有一些解决方案可以避免 SNAT 端口限制。 它们包括:
- 连接池:利用连接池,可以避免为对同一地址和端口的调用而打开新的网络连接。
- 服务终结点:使用服务终结点保护的服务没有 SNAT 端口限制。
- 专用终结点:使用专用终结点保护的服务没有 SNAT 端口限制。
- NAT 网关:使用 NAT 网关时,你会得到 64,000 个出站 SNAT 端口,通过该网关发送流量的资源可以使用这些端口。
为了避免 SNAT 端口问题,请避免对同一主机和端口反复创建新连接。 连接池是解决该问题更简单明了的方法之一。
如果你的目标是一个支持服务终结点的 Azure 服务,则可通过使用区域 VNet 集成和服务终结点或专用终结点来避免 SNAT 端口耗尽问题。 使用区域 VNet 集成并将服务终结点置于集成子网中时,发往这些服务的应用出站流量不会有出站 SNAT 端口限制。 同样,如果使用区域 VNet 集成和专用终结点,则不会有将流量发往该目标的出站 SNAT 端口的问题。
如果目标是 Azure 外部的外部终结点,则使用 NAT 网关可获得 64,000 个出站 SNAT 端口。 它还提供了一个专用出站地址,可以不与任何人共享。
如果可能,请对代码进行改进,以使用连接池并避免整个情况。 但更改代理并不是总能那么快,以致于无法及时缓解这种情况。 如果无法及时更改代码,可以利用其他解决方案。 该问题的最佳解决方法是尽量结合使用所有解决方案。 尝试对 Azure 服务使用服务终结点和专用终结点,并对其他服务使用 NAT 网关。
“Azure 的出站连接”文档的解决问题部分介绍了缓解 SNAT 端口耗尽问题的一般策略。 这些策略中的以下策略适用于托管在 Azure 应用服务中的应用和功能。
修改应用程序以使用连接池
- 对于池 HTTP 连接,请查看使用 HttpClientFactory 的池 HTTP 连接。
- 有关 SQL Server 连接池的信息,请查看 SQL Server 连接池 (ADO.NET)。
下面是有关通过不同的解决方案堆栈实现连接池的链接集合。
节点
默认情况下,NodeJS 的连接不会保持活动状态。 下面是适用于连接池的常用数据库和包,其中包含有关如何实现它们的示例。
- MySQL
- MongoDB
- PostgreSQL
- SQL Server
HTTP 保持活动状态
Java
下面是用于 JDBC 连接池的常用库,其中包含有关如何实现它们的示例:JDBC 连接池。
HTTP 连接池
PHP
尽管 PHP 不支持连接池,但你可以尝试使用到后端服务器的持久数据库连接。
MySQL 服务器
- 适用于较新版本的 MySQLi 连接
- 适用于较旧 PHP 版本的 mysql_pconnect
其他数据源
Python
下面是适用于连接池的常用数据库和模块,其中包含有关如何实现它们的示例。
HTTP 连接池
修改应用程序以重复使用连接
- 有关在 Azure Functions 中管理连接的其他指导和示例,请查看在 Azure Functions 中管理连接。
修改应用程序以使用主动性较低的重试逻辑
- 有关其他指导和示例,请查看重试模式。
使用 keepalive 重置出站空闲超时
- 若要实现 Node.js 应用的 Keep-Alive,请查看我的 Node 应用程序正在发出过多的出站调用。
特定于应用服务的其他指导:
- 将应用服务计划横向扩展为更多实例。 有关缩放的详细信息,请参阅缩放 Azure 应用服务中的应用。 应用服务计划中的每个辅助角色实例分配有多个 SNAT 端口。 如果将用量分散在多个实例之间,可能会使每个实例的 SNAT 端口用量不超过每个独特远程终结点的建议出站连接数限制(100 个)。
- 考虑转移到应用服务环境 (ASE),其中分配了单个出站 IP 地址,且连接数和 SNAT 端口数限制更高。 在 ASE 中,每个实例的 SNAT 端口数基于 Azure 负载均衡器预分配表。 例如,具有 1-50 个辅助角色实例的 ASE 每个实例有 1024 个预分配端口,而具有 51-100 个辅助角色实例的 ASE 每个实例有 512 个预分配端口。
避免超过出站 TCP 限制要更容易一些,因为这些限制是按辅助角色的大小设置的。 可以在沙盒跨 VM 数字限制 - TCP 连接中查看限制
限制名称 | 描述 | 小型 (A1) | 中型 (A2) | 大型 (A3) | 隔离层 (ASE) |
---|---|---|---|---|---|
连接 | 整个 VM 的连接数 | 1920 | 3968 | 8064 | 16,000 |
若要避免超过出站 TCP 限制,可以增大辅助角色的大小,或者横向扩展。
疑难解答
了解两种类型的出站连接限制以及应用的作用后,应该就可以更轻松地进行故障排除。 如果你知道自己的应用对同一存储帐户发出许多调用,可以怀疑达到了 SNAT 限制。 如果应用完全通过 Internet 向终结点发出大量的调用,可以怀疑达到了 VM 限制。
如果你对应用程序的行为认识不充分,以致无法快速判断原因,可以借助应用服务中的某些工具和技术做出判断。
查找 SNAT 端口分配信息
- 若要访问应用服务诊断,请在 Azure 门户中导航到你的应用服务 Web 应用或应用服务环境。 在左侧导航栏中,选择“诊断并解决问题”。
- 选择“可用性和性能”类别
- 在该类别下的可用磁贴列表中,选择“SNAT 端口耗尽”磁贴。 做法是将其保持在 128 以下。 如果确实需要,仍可以开具支持票证,支持工程师会从后端为你提取指标。
由于 SNAT 端口用量不是以指标形式提供的,因此无法基于 SNAT 端口用量进行自动缩放,也无法基于 SNAT 端口分配指标配置自动缩放。
TCP 连接和 SNAT 端口
TCP 连接和 SNAT 端口并不直接相关。 任何应用服务应用的“诊断并解决问题”管理页面中都包含了 TCP 连接用量检测程序。 搜索短语“TCP 连接”即可找到它。
- SNAT 端口仅用于外部网络流,而 TCP 连接总数包括本地环回连接。
- 如果协议、IP 地址或端口中的流不同,则一个 SNAT 端口可由不同的流共享。 TCP 连接指标统计每个 TCP 连接。
- TCP 连接限制在辅助角色实例级别发生。 Azure 网络出站负载均衡不使用 TCP 连接指标来限制 SNAT 端口。
- 沙盒跨 VM 数字限制 - TCP 连接中介绍了 TCP 连接限制
- 从 Azure 应用服务源端口添加新的出站 TCP 会话时,现有 TCP 会话会失败。 你可以使用单个 IP 或重新配置后端池成员以避免冲突。
限制名称 | 描述 | 小型 (A1) | 中型 (A2) | 大型 (A3) | 隔离层 (ASE) |
---|---|---|---|---|---|
连接 | 整个 VM 的连接数 | 1920 | 3968 | 8064 | 16,000 |
Web 作业和数据库连接
如果 SNAT 端口耗尽,导致 WebJobs 无法连接到 SQL 数据库,则不会有任何指标显示每个 Web 应用程序进程打开的连接数。 若要查找有问题的 Web 作业,请将多个 Web 作业移到另一个应用服务计划,以确定情况是否有所改善,或者某个计划中仍有问题。 重复该过程,直到找出有问题的 Web 作业。