【问题标题】:Outbound TCP Connection issue cause be sending data to event hub and data lake from azure function出站 TCP 连接问题导致从 azure 函数向事件中心和数据湖发送数据
【发布时间】:2018-10-09 18:34:46
【问题描述】:

我正在使用 http POST 触发器开发 Azure 函数,一旦客户端调用它并发布 json 数据,我会将其发送到事件中心并保存到数据湖。 一旦遇到高流量,20k/hour,azure functino 将产生高出站 TCP 连接,这将超过计划的限制(1920)。

  1. 高出站 TCP 连接是否由写入事件中心、数据湖或两者兼而有之?
  2. 有没有办法减少它,这样我就不必支付更多费用来升级我们的计划?
  3. 如何调试它来解决问题?

这里是发送数据到事件中心的代码:

EventHubClient ehc = EventHubClient.CreateFromConnectionString(cn);

try
{
  log.LogInformation($"{CogniPointListener.LogPrefix}Sending {batch.Count} Events: {DateTime.UtcNow}");

  await ehc.SendAsync(batch);

  await ehc.CloseAsync();
}
catch (Exception exception)
{
  log.LogError($"{CogniPointListener.LogPrefix}SendingMessages: {DateTime.UtcNow} > Exception: {exception.Message}");
  throw;
}

这是发送到数据湖的数据:

var creds = new ClientCredential(clientId, clientSecret);
var clientCreds = ApplicationTokenProvider.LoginSilentAsync(tenantId, creds).GetAwaiter().GetResult();

// Create ADLS client object
AdlsClient client = AdlsClient.CreateClient(adlsAccountFQDN, clientCreds);

try
{
    using (var stream = client.CreateFile(fileName, IfExists.Overwrite))
    {
        byte[] textByteArray = Encoding.UTF8.GetBytes(str);
        stream.Write(textByteArray, 0, textByteArray.Length);
    }

    // Debug
    log.LogInformation($"{CogniPointListener.LogPrefix}SaveDataLake saved ");
}
catch (System.Exception caught)
{
    string err = $"{caught.Message}Environment.NewLine{caught.StackTrace}Environment.NewLine";
log.LogError(err, $"{CogniPointListener.LogPrefix}SaveDataLake");
    throw;
}

谢谢,

【问题讨论】:

    标签: azure azure-functions azure-data-lake azure-eventhub


    【解决方案1】:

    TCP 连接的具体数量受到限制,具体取决于您的功能计划(消费或任何级别 B/S/P 中的静态计划)。 对于高工作量,我更喜欢

    A:使用具有单独函数的队列,并通过函数批量大小和其他设置限制并发

    B:使用 SemaphoreSlim 来控制传出流量的并发性。 (https://docs.microsoft.com/de-de/dotnet/api/system.threading.semaphoreslim?redirectedfrom=MSDN&view=netframework-4.7.2)

    【讨论】:

      【解决方案2】:

      我刚刚提出了 Azure SDK https://github.com/Azure/azure-sdk-for-net/issues/26884 的问题,报告使用 ApplicationTokenProvider.LoginSilentAsync 时出现套接字耗尽的问题。

      Microsoft.Rest.ClientRuntime.Azure.Authentication 的当前版本2.4.1 使用Microsoft.IdentityModel.Clients.ActiveDirectory 的旧版本4.3.0,每次调用都会创建一个新的HttpClientHandler

      在每个节点上创建 HttpClientHandler 是不好的。处理HttpClientHandler 后,底层套接字连接在很长一段时间内仍处于活动状态(根据我的经验,30 多秒)。

      有一个叫做HttpClientFactory 的东西可以确保HttpClientHandler 不会被频繁创建。这是来自 Microsoft 的指南,解释了如何正确使用 HttpClientHttpClientHandler - Use IHttpClientFactory to implement resilient HTTP requests。 我希望他们审查他们的 SDK 以确保他们遵循自己的准则。

      可能的解决方法

      Microsoft.IdentityModel.Clients.ActiveDirectory 自版本 5.0.1-preview supports passing a custom HttpClientFactory.

      IHttpClientFactory myHttpClientFactory = new MyHttpClientFactory();
      
      AuthenticationContext authenticationContext = new AuthenticationContext(
           authority: "https://login.microsoftonline.com/common",
           validateAuthority: true,
           tokenCache: <some token cache>,
           httpClientFactory: myHttpClientFactory);
      

      因此应该可以复制 ApplicationTokenProvider.LoginSilentAsync 在您的代码库中所做的事情,以创建 AuthenticationContext 并传递您自己的 HttpClientFactory 实例。

      你可能需要做的事情:

      • 确保将 5.0.1-preview 之后版本的 Microsoft.IdentityModel.Clients.ActiveDirectory 添加到项目中
      • 由于代码用于Azure函数,需要设置HttpClientFactory注入。更多信息可以在另一个StackOverflow answer找到
      • 用类似的东西替换调用ApplicationTokenProvider.LoginSilentAsync(tenantId, creds)(此代码是LoginSilentAsync 的内联版本,它将httpClientFactory 传递给AuthenticationContext
      var settings = ActiveDirectoryServiceSettings.Azure;
      var audience = settings.TokenAudience.OriginalString;
      var context = new AuthenticationContext(settings.AuthenticationEndpoint + domain,
          settings.ValidateAuthority,
          TokenCache.DefaultShared,
          httpClientFactory);
      
      var authenticationProvider = new MemoryApplicationAuthenticationProvider(clientCredential);
      
      var authResult = await authenticationProvider.AuthenticateAsync(clientCredential.ClientId, audience, context).ConfigureAwait(false);
      var credentials = new TokenCredentials(
          new ApplicationTokenProvider(context, audience, clientCredential.ClientId, authenticationProvider, authResult),
          authResult.TenantId,
          authResult.UserInfo == null ? null : authResult.UserInfo.DisplayableId);
      
      

      我真的没有复制解决方法中的逻辑,但我认为在Microsoft.Rest.ClientRuntime.Azure.Authentication 中正确修复之前没有其他选择

      祝你好运!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-13
        • 1970-01-01
        • 1970-01-01
        • 2020-01-24
        • 2016-07-24
        • 1970-01-01
        相关资源
        最近更新 更多