首页 文章

限制Azure Functions队列上的并发作业数

提问于
浏览
2

我在Azure中有一个Function项目,当项目放入队列时会触发该应用程序 . 它看起来像这样(大大简化):

public static async Task Run(string myQueueItem, TraceWriter log)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri(Config.APIUri);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        StringContent httpContent = new StringContent(myQueueItem, Encoding.UTF8, "application/json");
        HttpResponseMessage response = await client.PostAsync("/api/devices/data", httpContent);
        response.EnsureSuccessStatusCode();

        string json = await response.Content.ReadAsStringAsync();
        ApiResponse apiResponse = JsonConvert.DeserializeObject<ApiResponse>(json);

        log.Info($"Activity data successfully sent to platform in {apiResponse.elapsed}ms.  Tracking number: {apiResponse.tracking}");
    }
}

这一切都很好,运行得很好 . 每次将项目放入队列时,我们都会将数据发送到我们这边的某个API并记录响应 . 凉 .

当“产生队列消息的东西”出现大幅增加并且许多项目立即被放入队列时,就会出现问题 . 这往往会在一分钟内发生大约1,000-1,500件物品 . 错误日志将具有以下内容:

2017-02-14T01:45:31.692 mscorlib:执行函数时出现异常:Functions.SendToLimeade . f-SendToLimeade __- 1078179529:发送请求时发生错误 . 系统:无法连接到远程服务器 . 系统:通常只允许使用每个套接字地址(协议/网络地址/端口)123.123.123.123:443 .

起初,我认为这是Azure功能应用程序运行本地套接字的问题,如illustrated here . 但是,我注意到了IP地址 . IP地址123.123.123.123(当然在本例中已更改)是我们的IP地址,即HttpClient发布的IP地址 . 所以,现在我想知道是不是我们的服务器用完了套接字来处理这些请求 .

无论哪种方式,我们都会遇到扩展问题 . 我正试图找出解决问题的最佳方法 .

Some ideas:

  • 如果是本地套接字限制,article above有一个使用 Req.ServicePoint.BindIPEndPointDelegate 增加本地端口范围的示例 . 这似乎很有希望,但是当你真正需要扩展时,你会怎么做?我不希望这个问题在2年内回归 .

  • 如果's a remote limitation, it looks like I can control how many messages the Functions runtime will process at once. There'这是一篇有趣的文章,说你可以将 serviceBus.maxConcurrentCalls 设置为1,一次只能处理一条消息 . 也许我可以将它设置为相对较低的数字 . 现在,在某些时候,我们的队列填充速度将超过我们处理它们的速度,但此时答案是在我们的末端添加更多服务器 .

  • 多个Azure功能应用?如果我有多个Azure Functions应用程序并且它们都在同一队列上触发,会发生什么? Azure是否足够智能,可以在功能应用程序之间分配工作,我可以让大量机器处理我的队列,可以根据需要按比例放大或缩小?

  • 我've also come across keep-alives. It seems to me if I could somehow keep my socket open as queue messages were flooding in, it could perhaps help greatly. Is this possible, and any tips on how I' d去做这个?

对于这种系统的推荐(可扩展!)设计的任何见解将不胜感激!

4 回答

  • 5

    我想我已经在过去3小时6小时内运行了这些更改,并且我的零插槽错误 . 在我每30分钟左右大批量地收到这些错误之前 .

    首先,我添加了一个新类来管理HttpClient .

    public static class Connection
    {
        public static HttpClient Client { get; private set; }
    
        static Connection()
        {
            Client = new HttpClient();
    
            Client.BaseAddress = new Uri(Config.APIUri);
            Client.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
            Client.DefaultRequestHeaders.Add("Keep-Alive", "timeout=600");
            Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }
    }
    

    现在,我们有一个静态实例 HttpClient ,我们用它来调用函数 . 根据我的研究,强烈建议尽可能长时间地保留HttpClient实例,一切都是线程安全的,HttpClient会将请求排队并优化对同一主机的请求 . 注意我也设置了 Keep-Alive Headers (我认为这是默认的,但我认为我会隐含) .

    在我的函数中,我只是 grab 静态HttpClient实例,如:

    var client = Connection.Client;
    StringContent httpContent = new StringContent(myQueueItem, Encoding.UTF8, "application/json");
    HttpResponseMessage response = await client.PostAsync("/api/devices/data", httpContent);
    response.EnsureSuccessStatusCode();
    

    我还没有真正深入分析套接字级别发生的事情(我必须问问我们的IT人员是否能够在负载均衡器上看到这种流量),但我希望它只是保持单个套接字对我们的服务器开放,并在处理队列项时进行一堆HTTP调用 . 无论如何,无论它做什么似乎都在起作用 . 也许有人对如何改进有一些想法 .

  • 1

    我认为代码错误是因为: using (var client = new HttpClient())

    引自Improper instantiation antipattern

    这种技术不具备可扩展性 . 为每个用户请求创建一个新的HttpClient对象 . 在高负载下,Web服务器可能耗尽可用套接字的数量 .

  • 4

    如果您在专用Web应用程序上使用消费计划而不是功能,则开箱即用的#3或多或少 . 函数将检测到您有一个大的消息队列,并将添加实例,直到队列长度稳定 .

    maxConcurrentCalls 仅适用于每个实例,允许您限制每个实例的并发性 . 基本上,您的处理率是 maxConcurrentCalls * instanceCount .

    控制全局吞吐量的唯一方法是在您选择的大小的专用Web应用程序上使用函数 . 每个应用程序将轮询队列并根据需要抓取工作 .

    最佳扩展解决方案将改进123.123.123.123上的负载 balancer ,以便它可以处理来自函数扩展/缩小以满足队列压力的任意数量的请求 .

    保持活动afaik对于持久连接很有用,但是函数执行不会被视为持久连接 . 将来我们会尝试为函数添加“自带绑定”,如果你愿意,可以实现连接池 .

  • 1

    我知道很久以前就回答了这个问题,但与此同时,微软已经记录了你的反模式使用 .

    Improper Instantiation antipattern

相关问题