我建议研究诸如 Retry、Timeout、Circuit Breaker、Fallback 和 等模式>健康检查。或者,如果您关心并发调用和故障隔离,您也可以查看 Bulkhead 模式。
有许多资源解释了这些众所周知的模式,例如:
我不知道您使用的是哪个技术堆栈,但通常已经提供了一些针对这些问题的功能,您可以将这些功能整合到您的解决方案中。有些库已经处理了这种弹性功能,例如,您可以对其进行设置,以便在发生重试失败、超时、激活的断路器等事件时执行您的自定义代码。
例如对于 Java 堆栈 Hystrix 被广泛使用,对于 .Net,您可以查看 Polly .Net 以利用重试、超时、断路器、隔板或回退功能.
关于健康检查,您可以查看 Actuator for Java 和 .Net 核心已经提供了 health check middleware,它或多或少地提供了开箱即用的功能。
但在使用任何库之前,我建议先熟悉所列模式的目的和概念,以选择和集成最适合您的用例和主要关注点的模式。
更新
我们必须在这里区分两个众所周知的问题:
1.) 服务 A 如何稳健地处理服务 B 的临时中断(或服务 A 和 B 之间的网络连接归结为同样的问题)?
为了解决相关问题,上述模式将有所帮助。
2.) 如果服务A本身宕机,如何确保应该发送给服务B的请求不会丢失?
要解决这类问题,手头有不同的选择。
2a.) 对服务 A 执行请求(然后触发服务 B)的组件也应用上述弹性模式,并将重试其请求,直到服务 A 成功回答它已执行其任务(这也包括成功请求服务 B)。
每个服务也可以有多个实例,并且在这些实例前面有某种负载均衡器,它将请求分发并定向到特定服务的可用实例(基于定期执行的运行状况检查)。或者您可以使用服务注册表(请参阅https://microservices.io/patterns/service-registry.html)。
您当然可以一个接一个地链接多个 API 调用,但这可能会导致级联故障。所以我宁愿采用异步通信方法,如下一个选项中所述。
2b.) 让我们考虑一下,服务 A 的某个实例能够可靠地执行对服务 B 的请求是至关重要的。
在这种情况下,您可以使用 消息队列,如下所示:
- 假设您有一个队列,其中收集了要由服务 A 执行的作业。
- 然后,您有多个正在运行的服务 A 实例(请参阅水平扩展),其中每个实例将使用相同的队列。
- 您将使用消息队列服务的消息锁定 功能,以确保服务 A 的一个实例从队列中读取消息后,其他实例将看不到它。如果服务 A 能够完成它的工作(即调用服务 B,在服务 A 的持久性中保存一些状态以及成功处理需要包含的任何其他任务),它将从队列中删除消息之后 所以没有其他服务 A 实例也将处理相同的消息。
- 如果服务 A 在处理过程中出现故障,队列服务将自动为您解锁消息,并且服务 A 的另一个实例 A(或重新启动后的同一实例)将尝试从队列并尝试执行所有任务(调用服务 B 等)
您可以组合多个队列,例如还可以异步向服务 B 发送消息,而不是直接对其执行某种 API 调用。
关键是,队列服务是一些高度可用和冗余的服务,它已经确保一旦发布到队列就不会丢失任何消息。
当然,您也可以处理要在您自己的服务 A 数据库中执行的作业,但要考虑到当服务 A 收到请求时,总是有机会它在它之前停止运行可以将作业的状态保存到其持久存储以供以后处理。如果经过深思熟虑并正确使用,队列服务已经为您解决了这个问题。
例如,如果将 Kafka 视为消息传递服务,您可以查看此堆栈溢出答案,该答案与使用此特定技术时的问题解决方案有关:https://stackoverflow.com/a/44589842/7730554