确保为特定队列扩展不超过 N 个实例

ensuring no more than N instances are scaled out for a specific queue

我的功能是将负载发送到不同的 sftp 服务器。这些服务器在它们可以接受的连接数量上受到限制。

我需要一个解决方案来限制我们与这些服务器的连接。

函数由存储队列触发,设计初稿为:

然后我了解到每个函数只能有 1 个触发器,这让我想到了另一个聚合队列:

我可以在原始队列上设置 batchSize/newBatchThreshold,但我不确定这是否有效,因为原始队列不知道何时将消息推送到 聚合队列.

  1. 我需要的功能是不为来自队列 X 的所有消息扩展到超过 N 个实例,因为 sftp 服务器 X 不会接受超过 N 个连接。
  2. 此外,我需要该功能将来自队列 Y 的所有消息扩展到不超过 M 个实例,因为 sftp 服务器 Y 不会接受超过 M 个连接。

上述情况的实例总数为 M + N。

我们如何调整设计以满足这些要求?

没有 100% bullet-proof 的解决方案,已跟踪问题 here

最好的办法是在聚合队列触发的Function App的应用程序设置中将WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT设置为1。然后,您应该只获得一个 Function App 的并发实例,因此 batchSize 设置实际上对速率限制很有用。

在这种情况下,您不需要限制队列处理器X/Y/Z,让消息流向聚合。

现在,我不明白是只有来自队列 X 的消息接触 SFPT X,还是 many-to-many。如果是 one-on-one,那么去掉聚合队列,拥有三个 Function 并分别限制每个队列的并发是有意义的。

无论如何,限制设置是我上面建议的。

如果仍然不能满足您的要求,您可以切换到其他消息服务。例如,将一种类型的所有消息发送到 Service Bus 的单独会话或 Event Hub 的单个分区,这自然会限制代理级别的并发。

选项1:取决于sftp的错误响应

sftp 服务器 return 是否有 429(请求过多)响应?或者类似的东西?当您收到这样的响应时,您可以直接退出该函数,而无需从队列中删除消息。消息会在 30 秒后再次变为可见,并会触发一个函数。 30 秒是 visibilitytimeout 的默认值,是 customizable on per-msg 的基础。

方案二:分布式锁

我完全不知道带计数器的分布式锁定解决方案。另一种方法是使用 SQL 数据库和原子事务自行实现锁定解决方案。处理来自队列 X 的消息时的函数将查看数据库以查看 X 的锁定计数器是否小于 N,如果是则将其增加 1,然后处理消息。在这种情况下,您必须确保即使您的函数崩溃也能释放锁。即实现带租约到期时间的锁。