Azure 持久框架功能应用程序非常慢

Azure Durable Framework Function App VERY Slow

我制作了一个应用程序,它使用持久的 azure 函数 fan-out strategy 通过向我们自己的内部 API 发送 http 请求来对数据库进行并行查询和更新 API。

我发现扇出策略比使用 TPL library 并在普通 .net Core webapp 上以这种方式进行并行处理要慢得多。它不仅慢,而且慢了大约 20 倍。 130 次更新需要 10 分钟,而我为速度比较而制作的 .net core 3.1 应用程序执行完全相同的操作在 0.5 分钟内完成 130 次更新,而且计划要低得多。

我知道由于持久的框架基础设施(与存储帐户通信等)而存在延迟,但我不明白这种速度差异是如何正常的。每个单独的更新都发生在 ActivityTrigger 函数中,编排器负责收集所有必要的更新并将它们放入 Task.WhenAll() 调用中,就像 Microsoft 文档中的示例一样。

我是不是做错了什么?该业务场景是否可能与该技术不兼容?代码似乎工作正常并且并行性有效它只是比 .net 核心应用程序慢很多。另一件要提到的事情是,函数打开第二个实例的那一刻(由于它在消费计划中并且自然地打开第二个实例来处理重负载或者它在应用程序服务计划中并且我手动打开一个实例)它甚至尽管 cpu 负载在两个实例中以某种方式平衡,但速度较慢。我怀疑这可能是由于两个实例之间的 azure 队列通信导致的额外延迟,但我不完全确定。

最后一个细节是该应用程序还有一个 TimeTrigger,它每隔一分钟在数据库中执行一次简单的 select(甚至没有远程 cpu 密集,但它可能会影响性能).

我已经在高级计划、消费计划和应用服务计划中尝试过功能应用程序,无论计划有多大,它似乎都在 10 分钟内达到 130 次更新。

一般来说,TPL 几乎总是比 Durable Functions 快得多,因为所有协调都已完成 in-memory(假设在一台机器上做所有事情不会完全耗尽系统资源)。所以这部分通常是预期的。以下是一些值得了解的要点:

  • 每个 fan-out 到 activity 函数都涉及一组队列事务:一条消息用于调用 activity 函数,一条消息用于将结果返回给编排器。当涉及多个虚拟机时,您还需要担心队列轮询延迟。
  • 默认情况下,activity 函数的 per-instance 并发在 single-core VM 上限制为 10。如果您的 activity 函数不需要太多内存或 CPU,那么您需要调高此值以增加 per-instance 并发性。
  • 如果您使用的是 Azure Functions Consumption 或 Premium 计划,则需要 15-30 秒才能为您的应用添加新实例。如果您的工作负载可以通过 运行 在多台机器上更快地完成,那么这很重要。消息在队列上等待的时间是驱动 scale-out 的原因(1 秒被认为太长)。

您可以在 Durable Functions Performance and Scale documentation 中找到更多详细信息。

我要说的最后一件事是 Durable Functions 的关键增值是在分布式环境中以可靠的方式编排工作。但是,如果您的工作负载不是 long-running、不需要严格 durability/resilience、不需要 scale-out 到多个 VM,并且如果您有严格的延迟要求,那么 Durable Functions 可能不是正确的工具。如果您只需要一个 VM 并希望低延迟,那么使用 in-memory TPL 的简单函数可能是更好的选择。