我在 Azure 中有一个函数应用程序,当将项目放入队列时会触发该应用程序。它看起来像这样(大大简化):
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 Function 应用程序耗尽本地套接字的问题,因为此处图示。然而,后来我注意到了IP地址。 IP 地址 123.123.123.123(当然在本示例中有所更改)是我们的 IP 地址,即 HttpClient 发送到的 IP 地址。所以,现在我想知道是不是our服务器耗尽套接字来处理这些请求。
不管怎样,我们这里都存在一个扩展问题。我正在尝试找出解决该问题的最佳方法。
一些想法:
- 如果是本地套接字限制,上面的文章有一个使用增加本地端口范围的示例
Req.ServicePoint.BindIPEndPointDelegate
。这看起来很有希望,但是当你truly需要扩展吗?我不希望这个问题在两年后再次出现。
- 如果是远程限制,看起来我可以控制 Functions 运行时一次处理的消息数量。这里有一篇有趣的文章说你可以设置
serviceBus.maxConcurrentCalls
为 1 并且一次只会处理一条消息。也许我可以将其设置为一个相对较低的数字。现在,在某个时刻,我们的队列填满的速度将快于我们处理它们的速度,但那时的答案是在我们的一端添加更多服务器。
- 多个 Azure Functions 应用程序?如果我有多个 Azure Functions 应用程序并且它们都在同一队列上触发,会发生什么情况? Azure 是否足够智能,可以在功能应用程序之间分配工作,并且我可以拥有一大群机器来处理我的队列,并且可以根据需要扩大或缩小队列?
- 我也遇到过保持活动的情况。在我看来,如果我能以某种方式在队列消息涌入时保持套接字打开,也许会有很大帮助。这可能吗?关于我如何做到这一点有什么建议吗?
如果您对此类系统的推荐(可扩展!)设计有任何见解,我们将不胜感激!