微服务中的重试二


书接上文。上文提到了spring-retry和guava-retry,但针对重试的风险问题,并没有很好的解决。

重试治理

动态配置

采用中间件的方式实现重试功能,在其内进行RPC的重复调用,重试的配置信息存储在分布式配置中心。

配置的维度按照RPC调用特点选定 [调用方服务,调用方集群,被调用服务, 被调用方法] 为一个元组,按照元组来进行配置。

退避策略

上文中提到了重试时间间隔,决定这个间隔的方法叫退避策略,包括:

  • 线性退避:每次等待固定时间
  • 随机退避:一定范围内等待一个时间
  • 指数退避:连续退避,每次等待时间是上次的倍数

防止retry storm

上文提到的重试风险,主要是放大故障。为防止风险,可结合多种方法。

  1. 限制单点重试
    限制重试次数,更重要限制重试请求的成功率。采用断路器的思路,限制 请求失败/请求成功 的比率,给重试增加熔断功能。
    可以使用滑动窗口的方法实现,例如每个RPC维护一个滑动窗口,窗口内有N个bucket,每个bucket为1s内成功与失败的次数,在新请求这个 RPC 失败时,根据前 10s 内的 失败/成功 是否超过阈值来判断是否可以重试。

  2. 限制链路重试
    链路重试的理想情况是只有最后一层发生重试。

    Google内部使用特殊错误码实现,统一约定一个特殊的status code ,表示:调用失败,但别重试。一级失败后,生成该code返回给上层。

    这种方式对业务代码侵入性较大,bytedance则基于RPC协议的扩展字段实现,Response扩展字段中传递错误码标识,告诉上游不再重试。重试中间件中完成错误码生成、识别、传递等整个生命周期的处理。

    采用扩展字段的方式,需要考虑超时重传的问题。A—>B—>C的调用链,B—>C超时进行重试,此时A—>B拿不到响应,也超时重传,会有链路指数增大的效应。可以采取重试请求不重试的方法,在request中增加一个retry flag,B收到A的请求,先判断是否为重试请求,若是,则即便调用C失败也不重试;若否则重试C。这个flag会随着B的请求下传。

  3. 优化
    Backup Requests:预先设定一个阈值,比超时时间小,若请求发出超出该阈值,仍未响应,则再发送一个请求,两个请求中任意一个返回即可。即用访问量来换成功率 (或者说低延时) 的思想,发送第二个请求时,将第一个请求记为失败,并与熔断阈值进行比较。

    DDL:Deadline Request 调用链超时。是一种全链路式的调用超时,可以用来判断当前的 RPC 请求是否还需要继续下去。
    在 RPC 请求调用链中会带上超时时间,并且每经过一层就减去该层处理的时间,如果剩下的时间已经小于等于 0 ,则可以不需要再请求下游,直接返回失败即可。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值