Azure 函数遇到 System.Net.Sockets.SocketException
Posted
技术标签:
【中文标题】Azure 函数遇到 System.Net.Sockets.SocketException【英文标题】:Azure Function runs into System.Net.Sockets.SocketException 【发布时间】:2020-01-21 13:26:05 【问题描述】:我有带有 2 个 HTTP 触发函数的 AzureFunctions 应用程序。两者都来自同一个类,但使用不同的 url 来获取数据。 Azure 数据工厂管道每天都会触发第一个 HTTP 函数 另一个管道在 1 分钟内调用第二个函数
每个函数向第三方网站发出大约 1300 个 HTTP 请求,并将每个响应作为单独的 json 文件存储在 Blob 存储中。
问题几乎每次(但并非总是)第二个函数都会抛出 System.Net.Sockets.SocketException,因为很少有出站请求会遇到常见的 21 秒 TCP 超时。 我注意到奇怪的事情 - Azure 可能出于某种原因限制了我的出站请求:第一批需要近 300 毫秒,下一个序列需要 4.3 秒,然后是 9.5 秒,下一批达到 21 秒,但有异常
Here is image of timing increasing of outbound requests
异常堆栈跟踪:
System.Net.Http.HttpRequestException:连接尝试失败 因为连接方在一段时间后没有正确响应 时间,或建立连接失败,因为连接的主机有 未能响应---> System.Net.Sockets.SocketException: A 连接尝试失败,因为连接方没有正确 一段时间后响应,或建立连接失败 因为连接的主机未能在 System.Net.Http.ConnectHelper.ConnectAsync(字符串主机,Int32 端口, CancellationToken cancelToken) --- 内部异常结束 堆栈跟踪 --- 在 System.Net.Http.ConnectHelper.ConnectAsync(字符串主机,Int32 端口, CancellationToken 取消令牌)在 System.Threading.Tasks.ValueTask
1.get_Result() at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Threading.Tasks.ValueTask
1.get_Result() 在 System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask1 creationTask) at System.Threading.Tasks.ValueTask
1.get_Result() 在 System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancelToken) 在 System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage 请求,CancellationToken 取消令牌)在 System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage 请求,CancellationToken 取消令牌)在 System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage 请求,CancellationTokenSource cts,布尔值 处置)在 FunctionApp.BaseFunc.c__DisplayClass7_2.d.MoveNext() 在 E:\vsts-agent-win-1_work\339\s\Services\Host\Controllers\BaseFunc.cs:line 102 --- 从之前抛出异常的位置结束堆栈跟踪 --- 在 FunctionApp.BaseFunc.ProcessRun(ILogger 日志,字符串 runId) 在 E:\vsts-agent-win-1_work\339\s\Services\Host\Controllers\BaseFunc.cs:line 122.
FunctionApp 托管在 AppService 计划 S1 上,因此没有 600 个出站连接的限制(我相信是这样)
异常期间 TCP 连接的指标(最大值为 498): Metrics of AzureFunction App
来自 AzureFunction App 的“解决问题”助手的 TCP 连接 Max TCP connections in all states was 502
异常期间App服务计划的CPU和内存: App Service Plan metrics
应用是.Net Core 2.2
我没能在我的本地电脑上重现这个。但在 Azure 上,它几乎每天都会在每个环境(开发、测试、产品)上发生。 此类失败后,Azure 数据工厂会在 5 分钟后重试,每次都成功。
这是两个函数都使用的基类代码:
public abstract class BaseFunc
protected abstract string BlobFolderName get;
protected TelemetryClient telemetryClient;
private static HttpClient _httpClient;
static BaseFunc()
HttpClientHandler handler = new HttpClientHandler();
handler.MaxConnectionsPerServer = 300;
_httpClient = new HttpClient(handler);
protected async Task ProcessRun(ILogger log, string runId)
int processedItems = 0;
try
Stopwatch sw = Stopwatch.StartNew();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
await Authentication("url", log, runId); //sets default Authorization header
string getIdeaResult = await _httpClient.GetStringAsync("url");
JObject jsonObject = JObject.Parse(getIdeaResult);
int ideaCount = (int)jsonObject.SelectToken("total_count");
List<Task> tasks = new List<Task>();
string DataPulledDate = DateTime.Now.ToString("dd-MMM-yyyy");
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("connection string");
CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("container");
string getIdsUri = "url" + $"&limit=batchSize&offset=";
int iterations = (int)Math.Ceiling((decimal)ideaCount/batchSize);
for (int i = 0; i < iterations; i++)
string result = await _httpClient.GetStringAsync("url" + i * 50);
JObject jsonIdsObject = JObject.Parse(result);
int[] ideaIds = jsonIdsObject["content"].Children().Values<int>("id").ToArray();
foreach (int id in ideaIds)
tasks.Add(Task.Run(async () =>
string content = null;
using (var response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "url"+ id))) //Exception is thrown on this line
content = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference($"DataPulledDate/BlobFolderName/ideaId-id.json");
await cloudBlobContainer.CreateIfNotExistsAsync();
await cloudBlockBlob.UploadTextAsync(content);
Interlocked.Increment(ref processedItems);
));
await Task.WhenAll(tasks);
sw.Stop();
catch (Exception ex)
log.LogError(ex, "RunId: Run failed. Items items processed successfully, Exception: Exception.", runId, processedItems, ex.ToString());
throw;
finally
if (telemetryClient != null)
telemetryClient.Flush();
Thread.Sleep(3000);
函数本身的代码:
namespace FunctionApp
public class GetIdeas : BaseFunc
public GetIdeas(TelemetryClient telemetryClient)
this.telemetryClient = telemetryClient;
protected override string BlobFolderName get => "folder";
protected override string GetItemUrl get => "url";
[FunctionName("GetIdeasFn")]
public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
await ProcessRun(log, $"GetIdeasFn - DateTime.UtcNow.Ticks");
感谢任何帮助。
【问题讨论】:
您是否为每个连接创建一个新的BaseFunc
? aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
@Neil 感谢您的回复。否 - 在初始问题中添加了函数代码
您多久创建一次new GetIdeas
?如果每次“通话”一次,那么您就违反了我发布的链接。
@Neil 我没有实例化 GetIdeas。它是 Azure Function 的入口点。这就像以“始终开启”设置运行的 WebJob。所以应该一直运行。 Http调用从外部调用“运行”
抱歉,我错过了 BaseFunc
构造函数上的 static
。
【参考方案1】:
我遇到了同样的问题,但在我的情况下,有一个代码补丁具有一个长循环机制,它创建了数百个对 Microsoft GraphApi 的请求,并且没有响应一个请求,它正在创建另一个请求。已更正并修复问题!
【讨论】:
以上是关于Azure 函数遇到 System.Net.Sockets.SocketException的主要内容,如果未能解决你的问题,请参考以下文章
Azure 函数中的 Az.Functions 模块引发错误
高级计划中的 Python Azure 函数:函数的发布/部署失败……