我们之前说了,幂等的重要需求场景,接口超时重试,为了避免一个业务被执行了多次,接口需要支持幂等性
跟限流框架类似,幂等框架的功能性需求很简单,但是呢,对于一些非业务的需求,要求很高,比如业务的代码异常,业务的系统宕机了,幂等框架的异常,我们就针对这些异常情况,设计一个高度容错的幂等框架
幂等接口的正常处理流程
调用方从发起接口请求到接收到响应,一般要先发送请求到服务端,然后执行对应的业务逻辑,最后返回对应的执行结果,幂等框架在着三个阶段中
分别是,幂等号随着请求传递到接口实现方,接口实现方将幂等号解析出来,传递给幂等框架,幂等框架去查看幂等号是否已经存在,然后根据是否存在,来决定是否执行对应的业务逻辑
正常情况下,这是幂等框架的处理流程,但是,如果出现了异常,会根据出现在的不同阶段,有着不同的影响,比如第一个阶段出现了异常,发送请求失败或者超市,幂等号没有被记录,很好,很正常.
如果第三个阶段出现了异常,没法返回,业务已经执行过了,这时候幂等号已经记录了,重试也不会被执行,也符合逻辑
但是,对于第二个阶段业务执行过程出现了异常,处理起来就复杂多了,这就只能考虑如何去处理这个第二阶段的异常情况
1.首先是业务代码异常处理
首先分为了业务异常和系统异常来区分对待,什么是业务异常和系统异常呢?
(1).A用户发给消息给B用户,查询B用户存在,抛出自定异常,UserNotExisting
(2)访问数据库,数据库挂掉了,出现了这种异常,就是系统异常
对于业务异常,我们不会删除对应的幂等号,因为这种业务异常再次执行还是会触发的,对于系统异常,就可以将幂等号删除,重新执行这段代码,因为诸如数据库挂掉了,再启动还能执行成功
所以,为了提高框架的灵活性,低侵入业务逻辑,发生异常,是否再次重试,是交给业务的工程师来决定更加的合适,所以我们需要暴露对应的幂等号删除的接口,由开发人员决定是否真正的调用这个删除的接口,删除已经记录的幂等号
2.业务系统宕机处理
业务系统宕机了,幂等框架该怎么办
如果幂等号已经记录下了,但是那时候宕机了,业务再次触发也不会重试了,那么怎么办?
那么就是事务一致性的问题,必然希望,事务执行成功,记录幂等号,执行失败,幂等号记录被回滚,但是因为我们分别放在了SQL和Redis中,导致的分布式事务,所以,并不好解决
或者,我们采用另一种解决方案,就是,先进行存储业务数据的业务数据库,建立一个表记录幂等号,先存储到数据库中,在同步到Reids,折旧表保证了数据库的事务也行,保证了成功性,但是这个解决方案有一定的缺点,就是导致了和业务逻辑没有解耦,不符合低侵入,松耦合的设计思想
不过,我们不能昨晚尽善尽美,因为不知道这个框架会被应用到哪些个项目中,我们只要针对这些的可能异常,提供解决方案就可以了,可能不够完美,不够优雅,但是比编写一大堆的复杂的代码逻辑解决更好,我们建议业务系统记录SQL和幂等号的执行日志,方便进行幂等号的删除
3.幂等框架的异常处理
限流框架本身的异常,不能导致接口的响应异常,对于限流来说,限流框架执行异常,可能导致限流功能不能起作用,这样接口还能正常执行,这些异常会很快都被运维发现并修复,所以,短暂的限流失效,也不会对业务系统产生大量的影响,因为这是一个避免流量暴涨的接口,如果失效了可以接受
对于幂等来说,应对的是超时重试等特殊场景,但是,本来不应该重试的场景,因为幂等框架的错误被放开重试了,会导致不可预料的大量问题,于是,选择让接口的请求也失败,让对应的业务逻辑不重复执行,比业务执行出错,方便处理
本章重点:
幂等框架的设计思路,幂等框架的处理流程不难,因为,首先是拿到幂等号,根据幂等号是否已经存在来进行相对应的掉用或者取消
但是,对于幂等框架调用过程中存在的异常问题,需要进行思考和相对应的设计,
比如,业务上的代码异常,为了让幂等的框架更加的灵活,低侵入,是否在出现了异常,再去重试,交给开发这块的工程师来决定
对于业务系统的宕机,很少的异常,我们需要做到对出现问题的时候,能够记录对应的SQL和幂等的日志,方便后面的回滚
对于幂等框架的异常,和限流框架的异常不一样,在幂等逻辑执行异常的时候,选择让接口请求失败,相对应的业务逻辑直接不执行,业务就不会出错了,毕竟接口请求失败,比业务执行失败,修复成本低多了
课后思考:
在幂等框架中,除了我们讲到的异常,还会有其他的异常的出现吗?
框架本身在设计的时候,尽可能的考虑到相关的异常问题,一般都够触发项目的异常的,还是启动时候因为配置文件设置错误导致的异常问题,这就需要对配置文件的正确性进行校验
而且,对于幂等号,我们是否可以设置过期时间,来方便项目组件宕机后重启,直接使用,不用手动删除幂等号了