微服务之后端请求重试|青训营笔记

107 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第9天

重试的意义

本地函数调用通常没有重试意义

远程函数调用网络抖动、下游负载高、下游机器宕机...... 重试是有意义的,可以避免偶发性的错误,提高 SLA

重试的意义

降低错误率 降低长尾延时 容忍暂时性错误

请求重试的难点 幂等性 POST 请求可以重试吗? 重试风暴 随着调用链路的增加,重试次数呈指数级上升

超时设置

假设调用时间一共1s,经过多少时间开始重试?

gRPC的重试策略分为两类

重试策略,失败后进行重试

对冲策略,一次请求会给对端发出多个相同请求,只要有一个成功就认为成功

重试之时间策略 gPRC 指数避退+随机间隔 组合起来的方式进行重试

/* 伪码 */
ConnectWithBackoff()
  current_backoff = INITIAL_BACKOFF
  current_deadline = now() + INITIAL_BACKOFF
  while (TryConnect(Max(current_deadline, now() + MIN_CONNECT_TIMEOUT))
         != SUCCESS)
    SleepUntil(current_deadline)
    current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
    current_deadline = now() + current_backoff +
      UniformRandom(-JITTER * current_backoff, JITTER * current_backoff)

上面的算法里有这么几个关键的参数

INITIAL_BACKOFF:第一次重试等待的间隔 MULTIPLIER:每次间隔的指数因子 JITTER:控制随机的因子 MAX_BACKOFF:等待的最大时长,随着重试次数的增加,我们不希望第N次重试等待的时间变成30分钟这样不切实际的值 MIN_CONNECT_TIMEOUT:一次成功的请求所需要的时间,因为即使是正常的请求也需要有响应时间,比如200ms,我们的重试时间间隔显然要大于这个响应时间才不会出现请求明明已经成功,但却进行重试的操作。 通过指数的增加每次重试间隔,gRPC在考虑对端服务和快速故障处理中间找到了一个平衡点

限制重试比例

设定一个重试比例阈值(例如 1%),重试次数占所有请求比例不超过该阈值

防止链路重试

返回特殊的 status code,表示“请求失败,但别重试”

Hedged Requests

对于可能超时(或延时高)的请求,重新向另一个下游实例发送一个相同的请求,并等待先到达的响应

重试效果验证重试组件能够极大限制重试发生的链路放大效应

Z.png

【后端专场 学习资料四】第五届字节跳动青训营 - 掘金 (juejin.cn)