当前位置: 首页 > news >正文

【Azure App Service】App Service 里的 SNAT 端口 vs 出站连接数:到底是谁限制了谁?

问题描述

在 Azure App Service 中进行出站访问(Outbound Connection)时,我们都会遇到一个看似矛盾的现象:

  • 官方架构文档明确写着,每个实例允许的 TCP Connections(出站连接数)上限为 1920 / 3968 / 8064(分别对应 B1/S1/P1、B2/S2/P2、B3/S3/P3)。
  • 但在排查线上问题时,Azure 工程师或诊断工具却常常指出:每个实例大约只有 128 个 SNAT 端口,很容易被耗尽。

image

于是产生困惑:

  1. 这两个数字到底是同一回事的两种说法,还是两个独立的限制?
  2. 既然能开 8064 个连接,为什么只有 128 个 SNAT 端口?是不是哪里算错了?
  3. 真正限制我们应用代码能并发调用多少外部服务请求的,到底是哪一个?

本文会先把 SNAT 端口的占用原理 讲清楚,再解释它和出站连接 (Outbound Connections) 的区别。

 

问题解答

1. SNAT 端口到底是怎么被占用的

App Service 的 worker 实例没有自己的公网 IP。当应用访问公网 endpoint(例如 SQL、Storage、外部 API)时,流量会先到 stamp / scale unit 里的出站负载均衡器,由它把私网源地址改写成公网源地址,这个过程就是 Source Network Address Translation(SNAT)。

image

从应用视角看,它只是 connect 到外部服务。但从负载均衡器视角看,它必须为这条出站流维护一条映射记录:

字段示例值
Protocol TCP
Worker 实例 IP:port 10.0.5.60:51014
负载均衡器公网 IP:port 13.76.245.72:12481
外部 endpoint IP:port 52.189.232.180:1433

 

 

 

 

 

这里的 12481 就是这条 connect 在公网侧使用的 SNAT 端口。回包到达负载均衡器后,负载均衡器再根据映射表把包转回 10.0.5.60:51014。所以,SNAT 端口不是应用代码直接打开的端口,而是负载均衡器为了让回包找得到原始连接而分配的公网源端口。

 

2. SNAT 端口为什么容易被同一个后端耗尽 (非常重要)

理解 SNAT 占用,要先理解 TCP 流的唯一标识:五元组(5-tuple)

五元组字段含义示例
Protocol 协议 TCP
Source IP 源地址(SNAT 后 = 负载均衡器公网 IP) 13.76.2.72
Source Port 源端口(也就是 SNAT 端口) 12481
Destination IP 目的地址(外部 endpoint) 52.189.22.10
Destination Port 目的端口 1433

 

 

 

 

 

 

 

关键规则:只要五元组整体不重复,连接就是唯一的;如果五元组完全相同,负载均衡器就无法区分回包属于哪条流。

因此,SNAT 端口的占用规则可以这样理解:

  • 多条连接访问同一个目的 IP + 端口 + 协议:目的字段相同,只能靠不同的 Source Port 区分,所以 每条连接都要占一个新的 SNAT 端口
  • 多条连接访问不同目的 IP 或不同目的端口:目的字段已经不同,五元组天然不冲突,所以 可以共享同一个 SNAT 端口

下面用 同一个 SNAT 端口 12481 举例:

image

(此图对应原文描述:If your app creates connections to a mix of address and port combinations, you won't use up your SNAT ports. The SNAT ports are used up when you have repeated calls to the same address and port combination.

 

这就是为什么官方文档会强调:SNAT 端口限制主要影响反复连接同一个 address + port combination 的场景。典型例子包括:

  • 大量请求打到同一个 SQL Database;
  • 大量请求打到同一个 Redis / Storage endpoint;
  • Function App 被队列瞬间触发,所有实例或线程同时访问同一个外部 API。

 

3. 为什么每实例通常按 128 个 SNAT 端口估算

SNAT 端口来自负载均衡器公网 IP 的端口池,而不是单个 App Service 实例私有的无限资源:

  • 一个公网 IP 可用于 SNAT 的端口数量有限;
  • 一个典型 stamp /Scale Unit 有多个出站公网 IP,但要被 stamp/Scale Unit 内很多站点和实例共享;
  • App Service 每个实例通常会被预分配 128 个 SNAT 端口 作为安全估算值。

Azure 负载均衡器历史上有不同分配算法, 详见:SNAT with App Service -- https://4lowtherabbit.github.io/blogs/2019/10/SNAT/

image

 

4. SNAT 端口和 TCP Connections 的区别 (关键关键点)

回归到最初的困惑:

  1. 这两个数字到底是同一回事的两种说法,还是两个独立的限制?
  2. 既然能开 8064 个连接,为什么只有 128 个 SNAT 端口?是不是哪里算错了?
  3. 真正限制我们应用代码能并发调用多少外部服务请求的,到底是哪一个?

核心原因是:TCP ConnectionsSNAT 端口 描述的是同一条出站链路上的 不同动作、不同计数器、不同资源池。

  • TCP Connections:App Service 实例统计「当前有多少 TCP 连接」
  • SNAT 端口:只有连接需要访问外部公网 endpoint 时,才会在出站负载均衡器上消耗的公网源端口

 连接发起 ----> 到TCP Connection 计数 ---->  SNAT 端口消耗计数的流程图:

image

 TCP Connections / connect 和 SNAT 端口的区别可以概括为:

对比项TCP Connections / connectSNAT 端口
本质 connect 是建连动作;TCP Connections 是连接计数 负载均衡器公网侧的源端口资源
发生位置 Worker 实例沙箱 Stamp 出站负载均衡器
统计对象 Worker 上的 TCP 连接数量 公网侧源端口映射数量
是否包含本地 loopback 包含 不包含
是否只影响外部公网访问 否,所有 TCP 连接都会计入 是,主要用于外部网络流量
计数方式 每条 TCP 连接都算 1 条 同目标通常 1 条连接占 1 个端口;不同目标可能共享端口
常见上限 1920 / 3968 / 8064(按规格) 每实例通常按 128 估算
谁更常先触发 连接泄漏极严重时 高频访问同一外部后端时

 

 

 

 

 

 

 

 

 

 

可以把两者关系理解成:

  • connect 成功建立后,worker 上会多一条 TCP Connection;
  • 如果这条连接只是本地 loopback 或内部本地连接,它 只影响 TCP Connections,不影响 SNAT
  • 如果这条连接要访问外部公网 endpoint,它才会进入 SNAT 流程;
  • 进入 SNAT 后,是否新增一个 SNAT 端口,取决于目的 IP、目的端口、协议这些五元组字段是否已经可以区分流量。

所以二者 不是 1:1 关系

一条 TCP 连接可能不占 SNAT;

多条访问不同目标的 TCP 连接也可能共享 SNAT 端口;

但大量访问同一目标时,SNAT 端口会近似变成 1:1 的瓶颈。

 

总结

出站连接数(1920/3968/8064)是沙箱层的硬天花板,SNAT 端口(~128)才是 stamp 共享层、并且通常先撞到的现实瓶颈。

关键不是「我能开多少连接」,而是「我有没有复用连接」。

把每实例并发出站控制在 128 以内、复用连接、加快后端,SNAT 问题基本就不会找上门。

 

参考资料

Inside the Azure App Service Architecture : https://learn.microsoft.com/en-us/archive/msdn-magazine/2017/february/azure-inside-the-azure-app-service-architecture#network-port-capacity-for-outbound-network-calls

SNAT with App Service : https://4lowtherabbit.github.io/blogs/2019/10/SNAT/



 

 

 

 

 

http://www.gsyq.cn/news/1434334.html

相关文章:

  • RevitLookup终极指南:深度解析BIM数据透视与调试技术
  • 如何快速实现塞尔达传说跨平台存档转换:BotW-Save-Manager完全指南
  • 抖音视频批量下载终极指南:3分钟搞定用户主页完整备份
  • 郑州市 经开区 房屋修缮|维小达 专业窗户维修、吊顶维修、墙面修复、壁纸壁布铺贴、石材修复、瓷砖维修美缝一站式服务 - 维小达科技
  • 百度网盘限速终结者:BaiduPCS-Web与KinhDown完整免费加速指南
  • Unity 2022.3 导出 OBJ 模型到 Blender 的完整避坑指南(含坐标系、材质修复)
  • 量子梯度估计中的LCU方法:原理与应用
  • Windows 10 OneDrive 彻底卸载解决方案:专业级系统清理指南
  • 跨平台网络资源下载神器:3分钟快速上手res-downloader完整指南
  • 基于Arduino与ESP8266的智能灌溉系统:从传感器到手机控制的完整实践
  • 告别双边滤波的卡顿:用OpenCV的guidedFilter函数实现图像快速保边平滑(Python实战)
  • 如何用BiRefNet实现高精度图像分割:新手完整指南
  • 高三英语只有70分还有救吗?低分逆袭靠谱教育机构实测推荐 - 品牌测评鉴赏家
  • 如何免费下载无水印快手视频?KS-Downloader完整指南教你快速掌握
  • 基于Arduino的智能宠物喂食器:从传感器到伺服电机的完整物联网项目实践
  • 高三数学常年不及格?最后一年逆袭提分攻略|靠谱家教机构实测推荐 - 品牌测评鉴赏家
  • 深度探索Pearcleaner:如何让Mac应用清理变得智能又彻底?
  • Gemini对话写作跃迁指南:从机械复述到人格化表达的4阶认知升级路径
  • APC聚类与加权质心指纹:优化室内定位精度与效率的工程实践
  • Arduino水位控制器:从晶体管开关到自动灌溉的DIY实践
  • 如何快速修复损坏二维码:终极像素级编辑指南
  • Gemini误答事件全链路复盘,深度解析算法透明度、工程灰度发布与PR协同失效点
  • Gemini舆情分析结果可信度验证体系(含F1-score≥0.89的12项基准测试用例与审计清单)
  • 基于Arduino与TCS34725的糖果颜色分拣机:从硬件搭建到算法实现
  • 赛博朋克2077存档编辑器终极指南:5步掌握游戏自定义艺术
  • 青海路由心国际旅行社发布对外咨询与微信联系渠道:兰兰领队15297212390 - 行业深度观察
  • Arduino蓝牙遥控小车制作:从电机驱动到手机控制全解析
  • 株洲闲置名表变现哪家可信?4家门店探店实测 正规渠道选这些不踩坑 - 生活测评小能手
  • 如何免费激活Cursor Pro:3步实现AI编程工具无限使用方案
  • UE5独立游戏开发避坑:为什么你的多语言UI切换总失败?从独立进程测试到打包配置的完整流程