问题描述

当需要在应用中有大量的出站连接时候,就会涉及到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. http server源码解析

    本文主要过下http生成服务和处理请求的主要流程,其他功能并未涉及. 使用例子 const http = require('http'); http.createServer((req, res) = ...

  2. Jquery获取链接请求的参数

    比如有一个链接:https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000,先定义方法: //获取url中的参数 function ge ...

  3. java拼接JSON串

    String str = "{\"route\":\"onGift\",\"time\":\"\",\&quo ...

  4. Linux安装jdk(两种方式)

    最近在研究大数据方面的东西,业务场景是从设备采集数据经过处理然后存放DB. 建设上面的环境第一步肯定是安装jdk,所以和大家一起学一下基本知识centos7.5安装jdk1.8. 安装jdk有两种方法 ...

  5. 后端程序员之路 44、Redis结合protobuf

    protobuf序列化速度不错,在往Redis里存对象时,用protobuf序列化可以节省内存,省去写序列化反序列化代码的工作. google protocol buffer 与 redis 结合使用 ...

  6. Java编程开发之数据图表分析模型

    数据统计分析 多曲线图表分析实现 基本需求分析 假设在怪兽出没的年岁,加上年关在即,需要统计分析各个道路卡口车流量出入统计,主要从车流量和车牌地角度出发.如图所示的业务需求: 道路卡口-车流量分析: ...

  7. 别再恐惧 IP 协议(万字长文 | 多图预警)

    尽人事,听天命.博主东南大学硕士在读,热爱健身和篮球,乐于分享技术相关的所见所得,关注公众号 @ 飞天小牛肉,第一时间获取文章更新,成长的路上我们一起进步 本文已收录于 「CS-Wiki」Gitee ...

  8. CentOS7 下 MySQL 5.7.23 & XtraBackup 24 做数据备份(1)——安装软件

    在两台机子上同时操作下面的步骤 首先安装MySQL,从官网下载相对应版本的RPM包 mysql-community-client-5.7.23-1.el7.x86_64.rpm mysql-commu ...

  9. STL中常用容器及操作 学习笔记1

    @[TOC](下面介绍STL中常见的容器及操作)## 不定长数组 vector> vetcor:其实就是一个数组或者说是容器 其操作不同于之前直接定义的数组 > 而且可以直接赋值也可以直接 ...

  10. mysql 基本指令 1

    desc 表名  --查看表属性 show create table 表名 \g;  --查看代码 alter table 表名 auto_increment=20;  --改自增的值 MySQL:自 ...