3

我的服务是 DService,我是服务链中的第四个环节,即调用流程是 Online User -> AService -> BService -> CService -> DService -> EService。

当我从 DService 调用 EService 时,它​​会抛出像 HttpTimeoutException 这样的可重试异常。我通常重试 2-3 次,如果即使在 2-3 次重试后仍然失败,我也会抛出异常。

我的问题是,我向 CService 抛出的异常应该是可重试的还是不可重试的?请在下面找到我对这两种选择的优缺点的评估

从 DService 抛出可重试异常的缺点 - 如果 DService 抛出可重试异常,按照相同的约定,CService 也可能重试 DService 2-3 次,并且在每次 CD 调用中,D 将再次尝试 2-3 次 E 服务调用。同样,随着我们在调用链上的上升,最终对 EService 的调用将成倍增加。因此,如果 EService 网络确实长时间停机,我们正在谈论大量不必要的呼叫。这可以通过为链中的每个调用设置超时来缓解,但仍然不确定这是否足以缓解不必要的调用次数。

从 DService 抛出可重试异常的优点 - CService 将在某个时间后重试,因为在随后的重试中我们可能会得到正确的值(在时间限制内) - 特别是如果客户端是一些后端作业,那么他们可以在放弃之前以指数方式重试很长时间. 抛出 Un-Retriable 异常会清除此选项

请就此提出您的看法和建议

谢谢, 哈里什

4

4 回答 4

3

在不知道服务做什么的情况下,DService 应该重试还是 CService 应该重试,我不能肯定地说。但是我的理念是,被调用的服务不应该重试的服务,永远。在这种情况下,EService 会愚蠢地抛出异常,并且不做任何处理。这背后的原因是因为链的末端应该是无状态的,不应该代表调用者做出决定。

调用者可以在一定程度上在可接受和不可接受的范围内决定是否应该重新尝试错误。换句话说,如果EService试图连接数据库,而DService正在执行查找服务,那么如果在某个表中没有找到某个信息,则可能在DService的范围内进行签入另一张桌子。但是,EService 连接数据库失败的问题超出了 DService 的头,其范围只是返回 CService 请求的信息。

CService 已经调用以检索某些信息,具体取决于它所做的事情,然后可能会接收数据库连接并在延迟后尝试重试多次,因为它正在对该数据执行批处理工作并将继续重试直到数据库重新联机。或者,如果它正在检索要在网页上显示给用户的信息,则必须快速失败并通过向用户显示漂亮的错误消息来处理数据库连接错误。

这完全取决于您的服务做什么以及他们的责任在哪里。同样,异常是否可重试应该再次取决于调用者的必要性,而不是服务本身。向仅尝试一次的调用者提供可重试异常是完全可行的。

希望有帮助!

于 2016-03-11T11:26:44.303 回答
2

如果您在链上定义呈指数增长的重试周期,我认为抛出可重试异常是一种可行的方法。

于 2016-03-11T11:24:06.197 回答
1

我会说您首先不应该在 DService 中重试,因为正如您所说,如果每个服务都这样做,您可能会遇到麻烦。因此,让异常在调用堆栈中冒泡,并尽可能在最外层的服务中处理它;甚至可能是用户。

理由:为什么要由 DService 来决定 CService、BService 或 AService 是否要重试?

但是,我认为这也取决于异常的频率和重试的成功率。如果异常频繁发生,但调用通常在第一次或第二次重试时成功,则与每天发生一次的异常和/或大多数情况下重试是徒劳的相比,这是另一回事。

于 2016-03-11T11:22:51.793 回答
1

你扔给你的调用者的东西,以及你扔给他们的东西是否也会带有一个建议“但你可以重试这个”,应该由你的服务的预期语义专门确定。

(此外,我从未听说过正式带有任何此类属性的 java Exception 对象,但这可能是因为我有点落后了。)

编辑。

是否“重试”失败的操作,由(并且只有您自己)决定。但是,如果您确实决定重试,那么您也有责任决定在失败多少次后您将停止重试并每天调用它,此时向您的调用者抛出一个建议的异常肯定是不明智的他也可以“重试”。

于 2016-03-11T11:26:02.673 回答