优雅的重试下游接口

目录

重试治理的解决方案

业务接入成本低

动态配置

能够在链路级别防重试风暴

重试组件的功能

退避策略

限制单点重试

限制链路重试

重试请求不重试

超时场景优化

DDL


        服务调用链路中,经常会由于网络抖动等原因造成HTTP、RPC调用失败,这个时候失败重试机制可以提供请求的最终成功率,减少故障影响。但是这种重试机制会造成重试放大故障流量、链路放大的后果,所以一般大家不太敢重试,公司内部出现过多次因为重试而导致的事故,且出事故的时候还需要修改代码上线才能关闭重试,导致事故恢复也不迅速。

重试治理的解决方案

业务接入成本低

接入成本低的方式是采用服务框架的中间件形式,如gin的全局接口中间件,这样接入方增加一个全局的接口中间件即可。

动态配置

把重试的策略配置等信息,存放在分布式配置存储中心,服务启动自动拉取一次配置,控制面板更改配置后,主动/被动同步业务方中间件。

能够在链路级别防重试风暴

采用DDL的方式防止链路级别的重试

重试组件的功能

退避策略

一个重试组件所包含的基本功能中,除了重试次数和总延时这样的基础配置外,还需要有退避策略。对于一些暂时性的错误,如网络抖动等,可能立即重试还是会失败,通常等待一小会儿再重试的话成功率会较高,并且也可能打散上游重试的时间,较少因为同时都重试而导致的下游瞬间流量高峰。决定等待多久之后再重试的方法叫做退避策略,我们实现了常见的退避策略,如:

  • 线性退避:每次等待固定时间后重试。
  • 随机退避:在一定范围内随机等待一个时间后重试。
  • 指数退避:连续重试时,每次等待时间都是前一次的倍数。

限制单点重试

首先要在单点进行限制,一个服务不能不受限制的重试下游,除了限制用户设定的重试次数上限,更重要的是基于断路器的思想,限制 请求失败/请求失败 的比率,给重试增加熔断功能。我们采用了常见的滑动窗口的方法来实现,如下图,内存中为每一类 RPC 调用维护一个滑动窗口,比如窗口分 10 个 bucket ,每个 bucket 里面记录了 1s 内 RPC 的请求结果数据(成功、失败)。新的一秒到来时,生成新的 bucket ,并淘汰最早的一个 bucket ,只维持 10s 的数据。在新请求这个 RPC 失败时,根据前 10s 内的 失败/成功 是否超过阈值来判断是否可以重试。默认阈值是 0.1 ,即下游最多承受 1.1 倍的 QPS ,用户可以根据需要自行调整熔断开关和阈值。

限制链路重试

链路层面防止重试storm的核心是限制每层都进行重试,理想情况下只有最下一层(也就是最接近故障节点的一层才会重试)会有重试。Google SRE中约定Google内部调用链路上的每个节点失败后,返回特定的错误码告诉上游:调用失败,但别重试。当时这种方式对业务方要求较大,可以采用的方案是在公司级框架中间件中加入扩展自动,标识特定的错误码,上游中间件依赖这个返回码知道不做重试。Middleware 完成错误码的生成、识别、传递等整个生命周期的管理,不需要业务方修改本身的 RPC 逻辑,错误码的方案对业务来说是透明的。

重试请求不重试

通过在中间件的扩展字段中加入retry_flag的标志,标识本次为重试请求,如果重试请求失败,则不进行重试

超时场景优化

正常情况下的超时重试流程如下:

拿到 Resp1 (或者拿到超时结果) 后再发起第二次请求,整体耗时是 t1 + t2。ervice A 在发出去 Req1 之后可能等待很长的时间,比如 1s ,但是这个请求的 pct99 或者 pct999 可能通常只有 100ms 以内,如果超过了 100ms ,有很大概率是这次访问最终会超时,所有解决策略是提前重试。

我们预先设定一个阈值 t3(比超时时间小,通常建议是 RPC 请求延时的 pct99 ),当 Req1 发出去后超过 t3 时间都没有返回,那我们直接发起重试请求 Req2 ,这样相当于同时有两个请求运行。然后等待请求返回,只要 Resp1 或者 Resp2 任意一个返回成功的结果,就可以立即结束这次请求,这样整体的耗时就是 t4 ,它表示从第一个请求发出到第一个成功结果返回之间的时间,相比于等待超时后再发出请求,这种机制能大大减少整体延时。(但不是所有的业务场景都适合用这个策略)

DDL

DDL 是“ Deadline Request 调用链超时”的简称,我们知道 TCP/IP 协议中的 TTL 用于判断数据包在网络中的时间是否太长而应被丢弃,DDL 与之类似,它是一种全链路式的调用超时,可以用来判断当前的 RPC 请求是否还需要继续下去。如下图,字节跳动的基础团队已经实现了 DDL 功能,在 RPC 请求调用链中会带上超时时间,并且每经过一层就减去该层处理的时间,如果剩下的时间已经小于等于 0 ,则可以不需要再请求下游,直接返回失败即可,这样能做到最大限度的减少无用的重试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值