今天我们聊一聊 为什么系统需要重试?重试有何风险? x-retry 是什么?
随着微服务日益盛行,服务节点之间的调用也越来越频繁,经常由于网络抖动等系统原因导致服务之间调用失败,此时如果使用重试可以提高服务节点之间调用的成功率,提高系统的稳定性。
重试不仅提高系统的稳定性还可以提高系统的数据的一致性, 可能是服务与服务之间、服务与中间件之间都存在一致性要求。现有的分布式事务不仅系统复杂度较高,影响程序运行效率,因此往往是选择最终一致性,即通过重试补偿的形式,达到最终一致性
重试能够提高服务稳定性,但是一般情况下大家都不会轻易去重试,或者说不敢重试,主要是因为重试的流量不可控,且有放大故障,产生重试风暴的风险。由于没有统一的重试管理机制,服务各自为战,产生重试流量指数放大效应,导致链路上多层都被打挂,系统雪崩
重试还会存在链路放大的效应,结合下图说明一下
假设现在场景是 Backend A 调用 Backend B ,Backend B 调用 DB Frontend ,均设置重试次数为 3 。如果 Backend B 调用 DB Frontend ,请求 3 次都失败了,这时 Backend B 会给 Backend A 返回失败。但是 Backend A 也有重试的逻辑,Backend A 重试 Backend B 三次,每一次 Backend B 都会请求 DB Frontend 3 次,这样算起来,DB Frontend 就会被请求了 9 次,实际是指数级扩大。假设正常访问量是 n ,链路一共有 m 层,每层重试次数为 r ,则最后一层受到的访问量最大,为 n * r ^ (m - 1) 。这种指数放大的效应很可怕,可能导致链路上多层都被打挂,整个系统雪崩。
重试能提高系统的稳定性、保障数据一致性,但是重试也有一定的成本, 在一些公司内部没有统一的服务治理平台,基本都是各个业务系统各自为战,导致重试方案各不相同,比较简单就是使用 for 循环来实现,基本不会考虑重试的放大效应,这样很不安全,公司内部出现过多次因为重试而导致的事故,且出事故的时候还需要修改代码上线才能关闭重试,导致事故恢复也不迅速。
另外也有一些业务使用开源的重试组件,这些组件通常会考虑对直接下游的保护,但不会考虑链路级别的重试放大,另外需要业务方修改调用代码才能使用,对业务代码入侵较多,而且也是静态配置,需要修改配置时都必须重新上线。
基于以上的背景,为了让业务系统能够灵活安全的使用重试,我们实现了一个重试治理组件即x-retry具有以下优点: