分布式系统中工作流错误处理——以Infinitic为例
在分布式系统中,由于在不同服务中可能出现的各种潜在问题,错误处理本质上来说相当复杂。通常,这需要团队实施复杂的追踪系统来监控和排查错误。
Infinitic 通过自动跟踪错误链,并且可以直接在工作流中处理错误,让整个失败处理变得更简单。
Infinitic 是一个为 Java/Kotlin 应用程序设计的 基于事件的流程编排框架。它允许你编写工作流,就像它们在单一服务器上运行一样,但实际上是在由 Apache Pulsar 支持的分布式、事件驱动架构上运行。
在发布版本 0.17.0 后,Infinitic 引入了强大的新功能,使管理工作流错误前所未有的容易。
- 内置可靠性:无消息丢失,至少一次投递,优雅恢复
- 自动重试瞬时失败
- 自动将错误传递给父工作流
- 工作流级别支持手动或自动错误处理
Infinitic 是围绕 Apache Pulsar 构建的,Apache Pulsar 是一个分布式消息系统,确保组件间的消息可靠交换。Infinitic 中的任务由 服务执行器 处理,这些执行器处理特定领域的工作,比如库存管理、支付处理或用户管理。工作流,代表任务的高层次编排(例如完成订单),则由 工作流执行器 负责。
无论是服务执行器还是工作流执行器都具备水平扩展能力,这意味着可以添加额外的实例来处理增加的负载,从而确保系统的稳定性。然而,与任何分布式系统一样,错误可能在各个阶段发生,无论是由于 bug、网络问题、服务过载,还是人为交互的延迟或中断。这时,Infinitic 的错误管理功能就发挥作用了。
Pulsar 的通用保证Infinitic 依靠 Pulsar 来确保可靠的消息传递基础架构,确保提供以下关键保证:
- 无消息丢失:Pulsar 确保不会丢失任何消息。多区域集群甚至可以配置为缓解灾难性风险,例如该区域内所有消息日志的丢失。
- 至少一次投递:虽然 Pulsar 通常会将每个消息准确地投递一次,但在某些罕见情况下,消息可能会被消费多次。
- 从崩溃中平稳恢复:如果消费者(如服务或工作流执行器)因硬件问题或其他故障而崩溃,正在处理的消息将被释放,并最终被另一个实例消费。
这些保证构成了Infinitic确保任务和工作流可靠处理的基础,但比如任务或工作流失败时,又会发生什么呢?
处理瞬时失败在任何分布式系统中,临时故障是非常常见的。这些故障可能包括网络问题、服务过载或临时的 API 停机。Infinitic 处理这些问题的方式是自动重试失败的任务。
这些重试是可以自定义的,并可以根据具体用例进行精确调整,提供了处理失败的灵活性,使失败的管理更加灵活。此外,Infinitic 提供了一个任务 ID,可以将其用作幂等密钥,用来确保幂等性,这对于确保任务不会被重复执行非常关键。
不过,重试不一定能让任务最终能够成功。因此,在工作流程中制定应对任务失败的策略非常重要。
工作流级错误处理当一个Service Worker 在多次尝试后仍然无法处理任务时,Infinitic 会向请求的工作流任务发送一个错误消息。默认情况下,如果任务是同步请求,这将导致工作流失败。
相比之下,如果是异步请求的任务,那么失败不会立即引起工作流中的错误。
不过,如果工作流之后尝试获取某项失败的异步任务的结果,将引发异常:
在某些极端情况下——例如当 服务执行者 永久不可用或长时间不可用时——失败消息可能无法传递。为应对这种情况,Infinitic 允许用户在工作流层面设置超时。如果任务结果在指定时间内未返回,工作流将触发错误。
(请注意:超时的消息由Pulsar自己当作延迟消息来处理。)
手动错误处理步骤当工作流因为异常而失败时,通常会按照以下流程处理:……
- DevOps 认知:该问题通过系统的日志机制被检测到。
- 问题解决:DevOps 决定如何解决根本原因(例如修复服务错误或增加资源)。
- 重试失败的作业:一旦问题被解决,DevOps 可以使用 Infinitic 客户端来重试失败的任务。
- 自动恢复:任务成功后,工作流实例会自动从上次中断的地方继续执行。
Infinitic 还支持自动处理错误,使得可以直接在工作流中处理任务失败。这在预期会出现失败的情形下特别有用,例如,某个产品暂时缺货。
你可以在一个工作流中使用 [try…catch](https://docs.infinitic.io/docs/workflows/errors#try-catch-in-workflows)
块来确保即使某个任务失败,流程也能继续执行。例如,在一个场景中,假设有一个任务名为 taskA
,因业务限制而失败。通过用 try…catch
包裹该调用,可以确保即使 taskA
失败了,工作流也能继续。
try {
TaskResult result = myService.taskA(data)
} catch (TaskFailedEception e) {
// 处理任务失败的情况
处理失败
}
这种方法提高了工作流程的灵活性和恢复力,使其能够更灵活地应对失败。
解决异步任务中的问题正如之前提到的,异步任务不会立即导致工作流中的错误。然而,如果你想处理异步任务中的错误,你可以在子工作流中使用 try…catch
块来处理异步任务,或者在主工作流的其他部分使用 try…catch
块来处理。
这允许您在保持对主工作流程控制的同时异步地处理错误,请参阅文档。
当使用无穷状态时,也会自动将工作流中的异常传递给调用的工作流:
或者同步等待它的客户端应用程序:
此外,抛出的异常包含了导致当前状况的整个错误链的详尽信息。这为我们提供了一个深入了解根本原因并采取适当行动的机会,如有必要。
最后Infinitic的强大错误管理能力简化了在分布式系统中处理故障的过程。通过自动重试瞬时错误、跟踪错误并提供灵活的工作流配置,Infinitic确保复杂的工作流保持可靠、灵活且具有弹性。
无论您选择手动处理错误,还是利用Infinitic自带的自动错误处理功能,该平台都提供了高度灵活的错误管理方式,使构建和维护容错系统更简单。
我们鼓励您试试Infinitic,这样更口语化。无论您是开发新功能还是优化现有系统,Infinitic 提供所需的工具,而不会增加复杂性。为了获取定期更新、最佳实践和深入教程,可以考虑订阅我们的 Substack,这样语气更自然。
共同学习,写下你的评论
评论加载中...
作者其他优质文章