游乐游手机版
首页/AI教程/文章详情

Azure App Service SNAT源网络地址转换详解

时间:2026-06-06 16:39
AppService的worker实例通过出站负载均衡器进行SNAT转换访问外部服务。SNAT端口易因高并发访问同一目标、连接未复用而耗尽,表现为连接变慢、超时。解决方式包括复用连接、控制连接池大小、横向扩容实例等。

先说一个容易被忽视的事实:你的 App Service 应用在访问外部服务时——无论是 Azure SQL、Redis、Storage,还是某个第三方 API——并不是直接从 worker 实例“裸奔”到公网的。很多人会下意识这么认为,但背后的网络路径其实绕了个弯。

App Service 的 worker 实例运行在所谓的 scale unit(或者叫 stamp)内部,这些实例通常没有直接分配的公网 IP。当它们需要访问外部公网 endpoint 时,请求会先经过 stamp 的出站负载均衡器。这个负载均衡器会把 worker 的私网源地址和端口,转换成公网源地址和端口——这个过程,就是 SNAT(Source Network Address Translation)。

这篇文章打算系统性地梳理一下:在 App Service 环境中排查 SNAT 问题时,你需要知道哪些关键点。

  • SNAT 到底是怎么工作的?
  • SNAT 端口为什么会耗尽?
  • 端口是如何分配的?
  • 耗尽时有哪些典型症状?
  • 以及,应用应该如何优化连接的使用方式?

1: SNAT 是怎么工作的

以一次典型的 TCP 连接为例,出站访问的大致流程是这样的:

负载均衡器会为这次连接维护一条映射记录,举个例子:

字段示例
协议TCP
Worker 实例地址10.0.5.60:51014
负载均衡器公网地址13.76.245.72:12481
外部服务地址52.189.232.180:80

这里面有几个关键点需要注意:

  • 应用自身感知到的,是自己直接连到了外部服务;
  • 而外部服务看到的,是负载均衡器的公网地址在跟它通信;
  • 负载均衡器负责在两边之间做地址转换,整个过程对两端都是透明的。

2: SNAT 端口耗尽

SNAT 端口的消耗,本质上和 TCP 五元组密切相关。五元组由这些要素构成:

字段含义
Protocol协议,例如 TCP
Source IP源 IP,SNAT 后是负载均衡器公网 IP
Source Port源端口,也就是 SNAT 端口
Destination IP外部目标 IP
Destination Port外部目标端口

那什么情况下最容易把端口消耗掉呢?当多个 TCP 流访问的是同一个目标 IP、同一个目标端口、同一个协议时,它们必须使用不同的源端口来区分。换句话说,高并发地访问同一个外部服务,SNAT 端口会很快被吃光。反过来,如果这些请求分散到不同的目标 IP 或不同端口,五元组本身已经有了区分度,SNAT 端口就有机会被复用。

每个 IP 地址能打开的端口数量是有上限的。如果应用频繁地打开和关闭连接,情况会更严峻——因为 SNAT 端口关闭后并不会立即释放:

关闭方式SNAT 端口释放时间
正常 FIN/ACK 关闭约 240 秒后释放
RST 重置约 15 秒后释放
达到 idle timeout按 idle timeout 释放

算一笔账:如果一个 Web 应用每秒打开 1 条 HTTP 连接,调用后端服务后正常关闭,那么在 240 秒内,可能累计占用大约 240 个 SNAT 端口。

另一个典型场景是数据库连接池。假设一个繁忙站点的 SQL 连接池大小是 300,并且数据库查询执行得比较慢,那么这些连接可能会持续占用约 300 个 SNAT 端口。

还有一种很常见的情况是队列触发的 Function App。如果压测一开始就把大量消息一次性灌入队列,Function 可能会瞬间启动大量到 Storage 或其他外部服务的连接,很快就把 SNAT 端口耗尽了。

3: SNAT 端口分配算法

为了防止某个站点把整个 stamp 的 SNAT 端口都占光,从而影响到其他站点,Azure Load Balancer 需要对 SNAT 端口做分配控制。目前常见的有两种算法:

分配方式端口数量
On-demand 算法每实例基础 160 个,可按需尽力分配更多
新算法每实例固定预分配 128 个

这里的 160 个,可以用一个粗略的容量分摊思路来理解。一个典型的 App Service stamp 可能有 5 个出站 IP,每个 IP 理论上有大约 65536 个端口。如果这些端口要被 stamp 内大约 2000 个实例共享,算一笔简单的账:

5 × 65536 ÷ 2000 ≈ 163.84,取整后就是接近 160 个端口/实例。

4: SNAT 端口耗尽时的症状

当 SNAT 端口真的被耗尽时,应用通常会有这些表现:

  • 连接外部 endpoint 变得很慢;
  • 请求长时间 pending,迟迟得不到响应;
  • 最终出现 socket timeout;
  • 如果启用了 Application Insights 的 dependency tracking,会看到外部依赖调用失败。

5: 如何解决 App Service 的 SNAT 端口耗尽

解决问题的总体方向很明确:先想方设法减少不必要的连接占用,再考虑扩展资源。

具体来说,可以从以下几个方面入手:

  • 复用连接:不要每次都去 new 一个 HttpClient,这几乎是所有 SNAT 问题的头号元凶;
  • 使用连接池:无论是数据库连接还是 HTTP 客户端,都应当合理复用;
  • 控制连接池大小:连接池不是越大越好,过大的池子会持续占用端口资源;
  • 降低重试强度:失败时疯狂重试,只会让端口占用问题雪上加霜;
  • 让后端尽快响应:后端的响应时间越慢,连接存活得越久,SNAT 端口也就被占得越久;
  • 横向扩容 App Service Plan:SNAT 端口是按实例分配的,实例多了,总可用端口自然也会增加;
  • 考虑使用 App Service Environment:ASE 的实例池更小,每个 worker 实例通常能分配到更多的 SNAT 端口;
  • 压测要贴近真实流量:负载测试应该以稳定速度投喂数据,而不是一开始就把所有消息一股脑儿灌入队列。

示例代码及优化

下面这段代码,可以帮你复现 SNAT 端口耗尽的问题:

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";
}

下面这种写法也很容易造成 SNAT 端口泄漏,因为每次调用都会创建新的 HttpClient

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

改进后的做法是复用同一个 HttpClient

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

常见问题(FAQ):

Q:我能自己看到 App Service 的 SNAT 端口分配指标吗?
A:一般情况下,这个指标不直接公开。日常设计时,不要依赖“实际能拿到多少端口”,而应该按每实例 128 个的保守值来控制。

Q:为什么不能直接根据 SNAT 端口指标做自动扩缩容?
A:因为很多 SNAT 问题的根源是连接没有被复用。如果代码持续浪费连接,单纯扩容只是把问题摊开了,并不一定治本。正确的顺序是:先优化连接复用和后端响应,再考虑扩容。

Q:SNAT 耗尽和 TCP Connections 耗尽有什么区别?
A:TCP Connections 是 worker 实例层面的连接计数,而 SNAT 是出站负载均衡器上的公网源端口资源。前者统计的是所有 TCP 连接,后者只和外部网络流量相关。两者有关联,但不能互相替代。

Q:多个 WebJob 共用同一个 App Service Plan,怎么判断谁占用了最多连接?
A:如果没有按进程维度的连接指标,一个可行的办法是把部分 WebJob 移到另一个 App Service Plan,通过隔离法观察问题是否缓解,逐步定位到高连接消耗的任务。

参考资料

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

来源:https://developer.aliyun.com/article/1739467
上一篇腾讯云DeepSeek V4 API调用从入门到精通指南 下一篇Python+Pytest接口自动化测试实战方案
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
阿里云OpenClaw官方镜像六大场景3分钟开箱即用指南
AI教程 · 2026-06-06

阿里云OpenClaw官方镜像六大场景3分钟开箱即用指南

先聊聊OpenClaw到底是什么,以及它为什么值得关注。作为阿里云推出的智能助理平台,OpenClaw基于通义千问大模型深度定制,目标很明确:为开发者、创作者、运营者提供一站式的AI赋能解决方案。下面直接切入正题,看看它的六大核心场景。 OpenClaw 智能助理:六大核心场景赋能开发者高效成长 O

Moltbot Clawdbot与飞书机器人接入实践
AI教程 · 2026-06-06

Moltbot Clawdbot与飞书机器人接入实践

简单认识一下 Clawdbot 最近 AI 圈被一款名为 Clawdbot 的产品刷屏了。不管是在国内技术社区,还是刷 TG、X 的时候,几乎都能看到有人在讨论它。 看了一下官方文档,Clawdbot 本质上就是一个偏“个人智能助手”的东西。不过它并不是单独开一个网页给我们用,而是可以直接接入我们平

SpringAI与ONNX打造免费离线向量引擎
AI教程 · 2026-06-06

SpringAI与ONNX打造免费离线向量引擎

前段时间尝试了一个很有意思的项目——原本只是想在 Spring AI 项目中顺手集成 ONNX 模型,结果一上手就停不下来,直接调试到凌晨两点,边调边感慨:整个过程也太丝滑流畅了。 今天就来深入聊聊这件事:如何在 Spring AI 中使用 ONNX 向量模型,实现本地化的文本嵌入能力。 如果你之前

AI智能体技能完全指南:让你的AI助手拥有超能力
AI教程 · 2026-06-06

AI智能体技能完全指南:让你的AI助手拥有超能力

引言:AI Agent 的能力边界在哪里?你的AI编程助手可以编写代码,但它是否真正理解你公司的独特工作流程?能否自动处理你的CI CD流水线?又是否熟悉你日常使用的那些特定工具与API接口?AI Agent Skills正是为解决这一痛点而诞生的——它们作为可复用的能力模块,能够将通用型AI助手转

AI编程神器狂揽34k星与Claude Code和Codex绝配
AI教程 · 2026-06-06

AI编程神器狂揽34k星与Claude Code和Codex绝配

CC Switch:一站式AI编程工具管理神器 今天要介绍的这款实用小工具,名字叫作CC Switch。它是一款跨平台的桌面“All-in-One”助手,专门用于管理主流的AI编程开发工具。目前该项目在GitHub上已经获得了34k+ star,关注度非常高。它的核心卖点很直接:提供一个可视化操作界