如何在嵌套服务调用链中实现弹性(重试)

How to implement resiliency (retry) in a nested service call chain

我们有一个从 API 网关查询项目的网页,该网关又调用一个服务,该服务又调用另一个服务,依此类推。

网页 --> API 网关 --> 服务#1 --> 服务#2 --> 数据存储(RDMS、S3、Azure blob)

我们想使操作具有弹性,所以我们在每一层都添加了重试机制。

网页--重试-->API网关--重试-->服务#1--retry--> service#2 --retry--> data store.

然而,这可能会导致 cascading failure,因为如果数据存储没有及时响应,它会导致每一层超时并重试。换句话说,如果每一层都有相同的连接超时并配置为重试3次,那么数据存储将总共有81次重试(这称为重试风暴)。

解决此问题的一种方法是增加每一层的超时时间,以便让下面的层有时间重试。

网页--5m超时--> API网关--2m超时-->服务#1

然而,这是不可接受的,因为网页的超时时间太长。

我该如何解决这个问题?

是否应该只有一层重试?哪一层?该层如何知道错误是否是暂时的?

几个可能的解决方案(你 can/should 两者都用)是在不同的条件下重试并实施速率 limiters/circuit 断路器。

重试是一种技术,您不会在每个条件下都重试,而只会在特定条件下重试。这可能是特定的错误代码或特定的 header 值。例如。在你目前的情况下,不要重试超时;仅在服务器出现故障时重试。此外,您可以让每一层在不同条件下重试

速率限制是将本地或全局速率限制器服务内嵌到连接中。这将有助于 short-circuit 雷鸣般的牛群在它启动的情况下。例如。将数据层速率限制为 X req/s(在此处插入实际值)并将网关限制为 Y req/s,然后即使服务尝试多次重试,它也不会在链中传递太远。与此类似的是熔断,其中每一层只允许 X 个活动连接到任何下游,因此只是另一种减缓重试风暴的方法。