分布式系统容错性方案设计:重试与幂等

随着业务系统不断的发展,大的单体系统会逐渐拆分成多个独立的系统,或者多个微服务。有多个服务系统合作来完成一个复杂的业务。单体系统,拆分成多个微服务后,要完成的业务逻辑和原来的单体系统没有本质的差异,但是业务的可扩展性,可维护性都得到了很大的提升,微服务的好处都是老生常谈的内容,我这里不过多赘述。

但是,凡事有利有弊,拆分成微服务后,各个子业务逻辑的相互调用的实现方式,由原来单体系统中的进程内函数调用,在微服务场景下,变成了进程间的网络通信。

相比进程内的函数调用,进程间的网络通信出现故障的概率大幅度增加,例如网络不通,网络超时等,这些问题在进程内函数调用是不会出现的。

下面以服务间调用超时问题的处理,来讨论下微服务系统中容错性方案的分析与设计。

分布式系统中,微服务间的调用结果可以分为以下三种:成功,失败和超时。前两者都是明确的状态,而超时则是未知状态,结果是不确定的。

对于这种不确定的调用结果,常用的处理做法有两种:

1.下游系统提供处理结果查询接口。

2.重试。

处理结果查询接口

下游系统提供查询接口,为服务调用方提供了一种明确未知状态的方式,通过调用这个查询接口,可以明确调用的结果到底是成功了还是失败了,但是这种方式有一个不足之处,就是要为每一个可能出现问题的接口,都提供一个结果查询接口,这无疑增加了服务提供方的工作量,在复杂的业务系统中是不可取的。

重试

除了让下游系统提供结果查询接口外,让服务调用方进行重试,也是解决该问题的一个比较好的方法,该方式主要是让服务调用方针对返回不确定结果的请求进行重试,来获取确定结果的过程。不过这种方式需要服务被调用方支持幂等性处理,防止请求重试对服务提供方产生业务影响。

什么情况下需要重试? 这个由服务调用方根据调用返回结果来确定,相对比较简单,下面我们主要介绍下服务提供方对于幂等性处理的实现。

幂等

幂等实际上是数学中的一个概念,可以用公式 f(x)=f(f(x))来说明。而放在服务调用的场景中,幂等的意思是,针对一个接口,多次发起同一个业务请求,必须保证业务执行一次。

在实现幂等前,需要有一种手段,来区分:某个请求是重试的请求,还是正常请求。然后针对不同的请求进行不同的处理,通常用来区分两者的手段是给每个请求设置一个唯一性的id,来唯一标识一个请求。我们这里称这个id为请求id。这里需要满足:如果两个请求,是不同的请求,那么请求id不同,如果是重试请求,那么请求id和被重试的请求要相同。

全局id

用一个全局唯一的id,来作为请求的id,实现全局唯一性id的方式有一下两种:

1.全局id生成服务

如果有一个独立的服务来实现这个唯一id的生成,那么每一次请求都需要访问一下这个服务来获取请求id,这样会增加业务系统的复杂性,需要在原有业务流程中增加了获取请求id的流程,使原有的业务变得更复杂,增加了原有业务出现风险的几率,如下图所示:

在这里插入图片描述

2.服务调用方生成

如果有服务调用方生成的话,可以减少调用唯一id生成服务过程中产生的问题。但是由于服务调用方通常是集群部署的,如果请求id生成算法设计不好的话,可能会导致生成的请求id出现重复。

为了解决请求id重复的问题,我们需要一个不会重复的请求id生成算法,比如使用uuid(uuid有可能产生重复,但是概率很小),但是uuid字符串比较长,生成的id太过于随机,可读性也比较差,同时如果将请求id作为数据库索引的话,索引效率也是非常低的。

这里推荐一个分布式id生成算法,Twitter的开源项目Snowflake,它的核心思想是产生一个long型的id:

1.41bits作为毫秒数,大约可以使用69.7年

2.10bits作为机器编号,前5bits作为数据中心标识,后5bit作为服务器实例标识。

3.12bits作为毫秒内的序列号,一毫秒可以生成4096个序号,也就是每毫秒可以支持产生4096个id。

如下图所示:
在这里插入图片描述

幂等处理流程

利用id生成算法生成了无重复的请求id后,该如何利用这个请求id来实现业务层面的幂等性呢?

常用处理流程如下:

1.请求调用方的在请求中增加请求id参数

2.服务端解析出请求id,然后判断该请求id是否出现过,如果出现过则说明该请求是重试请求,进行重试请求的处理逻辑,否则是正常请求,进行正常请求的处理逻辑。

流程图如下:
在这里插入图片描述

其实,以上处理流程,存在可以优化的空间:重试请求量相对于正常请求量来说是少量的,也就是说,上述步骤2中,“判断请求id是否出现过"的结果,绝大部分情况下是没有出现过的,也就是对绝大部分的请求,执行"请求id是否出现过的操作”,都是在做无用功,

所以当每个请求过来的时候,不管这个请求是否是重试的,都将这个请求id插入到数据库中,如果这个请求是重试的话,那么这插入操作就会出现唯一键冲突,此时对于对于唯一键的冲突异常的处理就是对重试请求的处理。

到这里,我们对分布式系统容错性方案进行了分析和设计,主要针对的是,接口超时的这种case,除此之外,你觉得还有哪些case需要考虑,以及对应的解决方案是什么?欢迎评论区留言讨论。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值