问题描述

当需要在应用中有大量的出站连接时候,就会涉及到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。 负载均衡器的前端 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";
}

参考资料

使用 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

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

  1. 【应用服务 App Service】快速获取DUMP文件(App Service for Windows(.NET/.NET Core))

    问题情形 当应用在Azure 应用服务App Service中运行时,有时候出现CPU,Memory很高,但是没有明显的5XX错误和异常日志,有时就是有异常但是也不能明确的指出具体的代码错误.当面临这 ...

  2. 【应用服务 App Service】Azure 应用服务测试网络访问其他域名及请求超时限制(4分钟 ≈ 230秒)

    测试App Service是否可以访问其他DNS 当应用服务(Azure App Service)创建完成后,想通过ping命令来查看是否可以访问其他站点或解析DNS,但是发现ping命令无法使用.这 ...

  3. 【应用服务 App Service】App Service中抓取网络日志

    问题描述 众所周知,Azure App Service是一种PaaS服务,也就是说,IaaS层面的所有内容都由平台维护,所以使用App Service的我们根本无法触碰到远行程序的虚拟机(VM), 所 ...

  4. 【应用服务 App Service】解决无法从Azure门户SSH登录问题

    问题描述 中国区的Azure App Service(应用服务)已经支持创建Docker并选择Linux环境.在使用中,我们可以继续通过kudu站点的方式登录查看站点的一些日志及部署文件.它的登录方式 ...

  5. 【应用服务 App Service】Azure App Service 中如何安装mcrypt - PHP

    问题描述 Azure App Service (应用服务)如何安装PHP的扩展 mcrypt(mcrypt 是php里面重要的加密支持扩展库) 准备条件 创建App Service, Runtime ...

  6. 【应用服务 App Service】在Azure App Service中使用WebSocket - PHP的问题 - 如何使用和调用

    问题描述 在Azure App Service中,有对.Net,Java的WebSocket支持的示例代码,但是没有成功的PHP代码. 以下的步骤则是如何基于Azure App Service实现PH ...

  7. 【应用服务 App Service】发布到Azure上的应用显示时间不是本地时间的问题,修改应用服务的默认时区

    问题情形 应用程序发布到App Service后,时间显示不是北京时间,默认情况为UTC时间,比中国时间晚 8 个小时. 详细日志 无 问题原因 Azure 上所有的服务时间都采用了 UTC 时间. ...

  8. 【应用服务 App Service】当遇见某些域名在Azure App Service中无法解析的错误,可以通过设置指定DNS解析服务器来解决

    问题情形 当访问部署在Azure App Service中的应用返回 "The remote name could not be resolved: ''xxxxxx.com'" ...

  9. 【应用服务 App Service】当使用EntityFrameWorkCore访问Sql Server数据库时,在Azure App Service会出现Cannot create a DbSet for ** because this type is not included in the model for the context的错误

    问题情形 使用EF Core访问数据库,在本地运行正常,发布到App Service后,偶尔出现了Cannot create a DbSet for ** because this type is n ...

随机推荐

  1. tomcat部署项目问题

    tomcat部署项目的时候,报内存溢出,一种解决方案是直接添加内存,网上都有教程,如下: Windows下,在文件/bin/catalina.bat,Linux下,在文件/bin/catalina.s ...

  2. 微信小程序:数据绑定

    data中的数据不仅仅可以当成文本来显示,还可以当成属性来显示. 注意:属性值要用单引号或双引号引起来. 在微信开发者工具的控制台中点击Wxml会看到 使用Boolean类型充当属性的时候,字符串和花 ...

  3. C语言:试探算法解决“八皇后”问题

    #include <stdio.h> #define N 4 int solution[N], j, k, count, sols; int place(int row, int col) ...

  4. RocketMQ基础概念剖析,并分析一下Producer的底层源码

    由于篇幅原因,本次的源码分析只限于Producer侧的发送消息的核心逻辑,我会通过流程图.代码注释.文字讲解的方式来对源码进行解释,后续应该会专门开几篇文章来做源码分析. 这篇博客聊聊关于Rocket ...

  5. ubuntu系统共享桌面的使用和配置

    内容转载自我的博客 目录 1. ubuntu共享桌面 2. 局域网登录远程桌面 2.1 ubuntu使用remmina登录远程桌面 2.2 在windows登录远程桌面 2.3 Android使用RD ...

  6. HTML基础速览

    HTML概述 HTML ,CSS , JavaScript, JQuery, Vue 的关系 HTML可以写一个简单的前端,但是很丑,所以需要CSS对HTML进行美化 HTML是静态的.JavaScr ...

  7. 设置beeline连接hive的数据展示格式

    问题描述:beeline -u 方式导出数据,结果文件中含有"|"(竖杠). 执行的sql为:beeline -u jdbc:hive2://hadoop1:10000/defau ...

  8. Python-生成器

    创建生成器 创建生成器需要两部步骤 定义一个包含yield语句的函数 调用第一步创建的函数得到生成器 def test(val,step): 2 print("函数开始执行") 3 ...

  9. Tex中的引号(JAVA语言)

    package 第三章; import java.util.Scanner; public class Tex中的引号 { public static void main(String[] args) ...

  10. linux软件管理之yum管理操作软件包

    什么是rpm 1.1`RPM` 全称 `RedHat Package Manager` 缩写,由红帽开发用于软件包的安装.升级.卸载与查询. 1.2rpm包名组成部分 `RPM` 包命名以-将软件分成 ...