【Azure 应用服务】App Service/Azure Function的出站连接过多而引起了SNAT端口耗尽,导致一些新的请求出现超时错误(Timeout)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
应用型负载均衡 ALB,每月750个小时 15LCU
简介: 【Azure 应用服务】App Service/Azure Function的出站连接过多而引起了SNAT端口耗尽,导致一些新的请求出现超时错误(Timeout)

问题描述

当需要在应用中有大量的出站连接时候,就会涉及到SNAT(源地址网络转换)耗尽的问题。而通过Azure App Service/Function的默认监控指标图表中,却没有可以直接查看到SNAT是否耗尽的问题(可以间接参考App Service Plan级中Metrics的 Socket Outbound All指标[截图见文末附录一],但是由于它是整个Plan下所有App Service的汇总数据,不能直接表明SNAT是否超过128的限制)。

 

这里所说的出站连接如:SQL数据库, Redis缓存以及其他的Restful API等等需要从App Service中向外发出的请求。当SNAT耗尽后,会出现以下一种或多种问题:

  • App Service的响应速度缓慢。
  • 间歇性 5xx 错误或“错误的网关”错误
  • 超时错误消息
  • 无法连接到外部终结点(例如 SQL DB,Redis,及其他API等)

问题分析

因为App Service是部署在云服务中,所以它也遵循着一个集群中很多实例(VM)通过负载均衡器的前端 IP 建立出站连接,所以出站的端口就成了用于维护不同流的唯一标识符。 因为在网络流量的五元组中

  1. 目标 IP
  2. 目标端口
  3. 源 IP
  4. 源端口
  5. 协议

如访问Redis服务(redistest01.redis.cache.chinacloudapi.cn 6380),目标IP为固定不变为RedisHost,而端口则固定为6380,源IP为当前App Service的出站IP,协议方式为Redis的序列化协议(RESP)。以上1,2,3,5都不可变的情况下,只有4 源端口可以改变,所以这里就需要使用SNAT

 

如App Service中一个示例(Worker Instance)发送TCP协议,介绍SNAT的工作流程:

1)App Service应用发送一个TCP包到外部IP地址,源地址和端口在TCP包中。

2)TCP包从App Service应用的工作实例上发送到SNAT负载均衡,SNAT改变了TCP包中的源地址为负载均衡器的公共IP地址和端口号。然后发送到外面目标IP地址。

Attribute Value
Protocol TCP
Worker instance IP address:port 10.0.5.60:51014
Load balancer IP address:port 13.76.245.72:12481
External endpoint IP address:port 52.189.232.180:80

3)外部服务接收到这个TCP包后,会原路回包,它会使用负载均衡器的公共IP地址和端口后作为目标IP和端口。

4)当负载均衡器收到外部服务的回包后,它将根据第2步中的映射关系,修改TCP包中的目标IP和端口。如此TCP回包就正确的回到了App Service的工作实例上。

 

负载均衡器的前端 IP 分配的每个公共 IP 都会为其后端池成员分配 64,000 个 SNAT 端口,后端池中大约有400多个实例,所以大约分配到每个实例的SNAT端口为64,000/400 =160(最大), 但是实际上分配的个数为128个。

 

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

  • TCP 连接数:可以建立的出站连接数有限制。 对出站连接的限制与使用的辅助角色的大小关联。
  • SNAT 端口: Azure 使用源网络地址转换 (SNAT) 和负载均衡器 (不向客户公开,) 与公共 IP 地址进行通信。 最初为 Azure 应用服务中的每个实例预分配了 128 个 SNAT 端口。 SNAT 端口限制会影响与相同地址和端口组合的打开连接。 如果应用与混合的地址/端口组合建立了连接,则不会用尽 SNAT 端口。 重复调用同一个地址/端口组合时,会用尽 SNAT 端口。 释放某个端口以后,即可根据需要重复使用该端口。 只有在等待 4 分钟后,Azure 网络负载均衡器才会从关闭的连接回收 SNAT 端口。

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

 

解决办法

避免 SNAT 端口问题意味着需要避免对同一主机和端口反复创建新连接。 连接池是解决该问题的更显而易见的方法之一。

如短时间无法修改代码,基于App Service, Azure Function的易扩展的特性,可以增加实例个数来及时缓解SNAT的受限问题。当每增加一个实例,SNAT端口即可增加128个。

 

建立连接池的方式一:HttpClientFactory 建立 HTTP 连接池

尽管 HttpClient 实现了 IDisposable 接口,但它是为重复使用而设计的。 关闭 HttpClient 的实例使套接字在 TIME_WAIT 一小段时间内处于打开状态。 如果经常使用创建和处置对象的代码路径 HttpClient ,应用可能会耗尽可用的套接字。 ASP.NET Core 2.1 中引入了HttpClientFactory作为此问题的解决方案。 它处理池 HTTP 连接以优化性能和可靠性。

建议:

  • 不要 直接创建和释放 HttpClient 实例。
  • 请 使用 HttpClientFactory 来检索 HttpClient 实例。

示例部分

1)以下代码即可复现SNAT快速耗尽的情况(没有及时释放Response资源)

public string Index(string url)
{
    var request = HttpWebRequest.Create(url);
    request.GetResponse();
    return "OK";
}

可以修改为:

public string Fin(string url)
{
    var request = HttpWebRequest.Create(url);
    var response = request.GetResponse();
    response.Close();
    return "OK";
}

 

2)下面使用Using来释放httpclient对象,但是也是用以导致SNAT耗尽的问题。

public async Task<string> Client(string url)
{
    using (var client = new HttpClient())
    {
        await client.GetAsync(url);
    }
    return "OK";
}

可以考虑重用HttpClient来缓解SNAT耗尽问题

private static Lazy<HttpClient> _client = new Lazy<HttpClient>();
public async Task<string> ReuseClient(string url)
{
    var client = _client.Value;
    await client.GetAsync(url);
    return "OK";
}

 

附录一:应用服务计划中查看全部的出站Socket连接

 

 

 

参考资料

使用 SNAT 进行出站连接(负载均衡器默认端口分配) : https://docs.microsoft.com/zh-cn/azure/load-balancer/load-balancer-outbound-connections#default-port-allocation

排查 Azure 应用服务中的间歇性出站连接错误:https://docs.microsoft.com/zh-cn/azure/app-service/troubleshoot-intermittent-outbound-connection-errors#avoiding-the-problem

SNAT with App Service,介绍Azure App Service中SNAT的原理,问题,及如何避免?:https://www.cnblogs.com/lulight/articles/13543209.html

相关实践学习
基于ACK Serverless轻松部署企业级Stable Diffusion
本实验指导您在容器服务Serverless版(以下简称 ACK Serverless )中,通过Knative部署满足企业级弹性需求的Stable Diffusion服务。同时通过对该服务进行压测实验,体验ACK Serverless 弹性能力。
目录
打赏
0
0
0
0
203
分享
相关文章
基于STM32的智能手环wifi连接手机APP(下)
基于STM32的智能手环wifi连接手机APP(下)
312 0
HTTPS为什么可以穿越NAT端口映射设备
HTTPS能穿越NAT端口映射设备的原因在于,NAT设备仅在IP和端口层面进行地址转换,不对应用层协议(如TLS)的内容进行解析或干预。因此,HTTPS的加密通信可在客户端与服务器间直接建立,NAT设备充当透明中介,确保数据包正确路由,而不涉及加密或认证过程。这样即使没有在NAT设备上配置证书,HTTPS连接也能顺利建立并保持安全。
132 6
基于STM32的智能手环wifi连接手机APP(上)
基于STM32的智能手环wifi连接手机APP(上)
298 0
|
8月前
【Azure Logic App】使用Event Hub 连接器配置 Active Directory OAuth 认证无法成功连接到中国区Event Hub的解决之法
An exception occurred while retrieving properties for Event Hub: logicapp. Error Message: 'ClientSecretCredential authentication failed: AADSTS90002: Tenant 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' not found. Check to make sure you have the correct tenant ID and are signing into the correct cloud. Che
【Azure API 管理】APIM不能连接到 App Service (APIM cannot connect to APP service)
【Azure API 管理】APIM不能连接到 App Service (APIM cannot connect to APP service)
|
9月前
|
C++
【Azure Logic App】使用Event Hub 连接器配置 Active Directory OAuth 认证无法成功连接到中国区Event Hub
【Azure Logic App】使用Event Hub 连接器配置 Active Directory OAuth 认证无法成功连接到中国区Event Hub
|
9月前
【Azure Function】在Function执行中遇见Timeout错误
【Azure Function】在Function执行中遇见Timeout错误
【Azure Logic App】微软云逻辑应用连接到数据库,执行存储过程并转换执行结果为JSON数据
【Azure Logic App】微软云逻辑应用连接到数据库,执行存储过程并转换执行结果为JSON数据
【Azure Logic App】微软云逻辑应用连接到数据库,执行存储过程并转换执行结果为JSON数据
【一步步开发AI运动APP】七、自定义姿态动作识别检测——之规则配置检测
本文介绍了如何通过【一步步开发AI运动APP】系列博文,利用自定义姿态识别检测技术开发高性能的AI运动应用。核心内容包括:1) 自定义姿态识别检测,满足人像入镜、动作开始/停止等需求;2) Pose-Calc引擎详解,支持角度匹配、逻辑运算等多种人体分析规则;3) 姿态检测规则编写与执行方法;4) 完整示例展示左右手平举姿态检测。通过这些技术,开发者可轻松实现定制化运动分析功能。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等