排查Durable Functions并行运行仍缓慢的问题
我们实现了基于Fan Out模式的Durable Orchestrator函数,用于将日期范围任务拆分为多段并行处理,代码如下:
[FunctionName("process-orchestration")] public async Task ProcessOrchestrationAsync( [OrchestrationTrigger] IDurableOrchestrationContext context) { var runProcessEvent = context.GetInput<RunProcessDto>(); var processStartedAt = context.CurrentUtcDateTime; // 1. 初始化流程 var initialiseProcessResponseDto = await context.CallActivityAsync<InitialiseProcessResponseDto> ("initialise-process-activity", ); // 2. 并行运行分段任务 var tasks = new List<Task<RunProcessSegmentResponseDto>>(); foreach (var runProcessRequestDto in initialiseProcessResponseDto.RunProcessRequestDtos) { var subTask = context.CallActivityAsync<RunProcessSegmentResponseDto>("run-process-segment-activity", runProcessRequestDto); tasks.Add(subTask); } await Task.WhenAll(tasks); // 3. 聚合结果 var runProcessSegmentResponseDtos = new List<RunProcessSegmentResponseDto>(); foreach (var eachTask in tasks) { var taskResult = eachTask.Result; runProcessSegmentResponseDtos.Add(taskResult); } var aggregateProcessResultDto = new AggregateProcessResultDto() { RunProcessRequestDto = new RunProcessRequestDto() { NoOfDays = runProcessEvent.NoOfDays, }, RunProcessSegmentResponseDtos = runProcessSegmentResponseDtos }; var runProcessResponseDto = await context.CallActivityAsync<RunProcessResponseDto>("aggregate-process-result-activity", aggregateProcessResultDto); // 4. 完成流程 runProcessResponseDto.ProcessStartedAt = processStartedAt; runProcessResponseDto.ProcessFinishedAt = context.CurrentUtcDateTime; await context.CallActivityAsync<RunProcessResponseDto>("finalise-process-activity", runProcessResponseDto); }
整体流程正常,但部分天数少的日期段处理耗时异常久,诊断数据如下:
开始日期: 03/07/2022 结束日期: 01/10/2022 总天数: 90 流程启动时间: 01/10/2022 10:02:48 GMT 流程结束时间: 01/10/2022 11:41:51 GMT 分段1: 开始日期: 03/07/2022 结束日期: 18/07/2022 启动时间: 01/10/2022 10:02:48 结束时间: 01/10/2022 11:41:36 分段2: 开始日期: 19/07/2022 结束日期: 03/08/2022 启动时间: 01/10/2022 10:02:48 结束时间: 01/10/2022 11:37:26 分段3: 开始日期: 04/08/2022 结束日期: 19/08/2022 启动时间: 01/10/2022 10:02:48 结束时间: 01/10/2022 11:35:59 分段4: 开始日期: 20/08/2022 结束日期: 04/09/2022 启动时间: 01/10/2022 10:02:48 结束时间: 01/10/2022 11:17:13 分段5: 开始日期: 05/09/2022 结束日期: 20/09/2022 启动时间: 01/10/2022 10:02:48 结束时间: 01/10/2022 10:19:05 分段6: 开始日期: 21/09/2022 结束日期: 01/10/2022 启动时间: 01/10/2022 10:02:48 结束时间: 01/10/2022 10:14:03
我们已尝试以下优化但无改善:
- 升级至最高规格Premium函数实例
- 在host.json中配置并行限制:
"extensions": { "durableTask": { "hubName": "%HubName%" }, "maxConcurrentActivityFunctions": 5, "maxConcurrentOrchestratorFunctions": 5 }, "functionTimeout": "-1"
请问还有哪些未考虑到的性能影响因素?
数据分布不均:虽然日期段的天数一致,但不同时间段的业务数据量可能差异极大。比如7-8月的订单、日志等数据量远高于9月,导致对应分段的实际处理负载远超其他段,即使实例规格足够,也会因为数据量过大耗时更久。需要检查各分段对应的实际数据行数、计算量差异。
外部资源争抢:活动函数依赖的外部资源(如数据库)可能存在连接池限制,多个并行任务同时争抢连接时,早期启动的分段可能因等待连接被阻塞,而后期启动的任务反而先获取到资源完成处理。需要检查数据库连接池配置,以及活动函数中是否有长时间的资源等待逻辑。
活动函数内部低效逻辑:旧日期段的处理可能涉及特殊逻辑分支(如历史数据归档校验、旧业务规则计算),或者存在未优化的查询(如未使用索引、全表扫描)。比如7月的数据存储在归档表中,查询速度远慢于9月的在线表;或者针对旧数据的计算逻辑更复杂,导致耗时增加。需要单独测试不同日期段的活动函数执行耗时,定位具体瓶颈。
Durable Task Hub存储性能瓶颈:Durable Orchestrator的状态、事件存储在后端存储服务中,如果存储账户的IOPS、吞吐量达到限制,会导致任务状态更新、事件传递延迟,进而影响活动函数的调度效率。特别是多个并行任务同时更新状态时,存储的IO瓶颈会被放大。需要检查存储账户的性能指标是否达到阈值。
外部依赖性能波动:活动函数可能依赖第三方API、缓存服务等外部资源,旧日期段的请求可能因为外部服务的限流、性能降级而变慢。比如调用历史数据查询接口时,响应速度远低于近期数据接口,导致分段处理耗时增加。需要监控活动函数中外部调用的响应时间。
内容的提问来源于stack exchange,提问作者Paul

