前言
最近另一个团队在群里@我们的小伙伴,说根据业务唯一标识请求获取文件链接接口失败,我们这边立马开始了排查。该业务唯一标识在我们这边数据库查询不到,有些怀疑唯一标识是不是给错了,但是根据命名规则确实是我们系统生成的。随后排查了最近30天日志,发现了该唯一标识。进一步确认了异常所在,是下面代码造成的
这里存在的问题是什么呢,伪代码如下:
public Result submitV3(AuthReq req) {
//第一步:通知下游接口(唯一标识)
//第二步:成功,落库,生成文件,3秒主动超时
}
- 由于调用方系统设置了主动3s超时,在被调用方系统接口响应慢超过3s的情况下,主动断开抛出超时异常。
- 被调用方系统由于收到了请求,在慢慢处理中,最终成功了。
问题定位
上面就造成了数据状态的不一致。那么如何解决呢?
- 如果请求量不大的情况下并且cpu资源比较充足情况下,超时可以长一些
- 请求量大且性能要求高的场景,可以要求被调用方系统提升接口性能。
继续思考一下,上述就一定可以解决吗,这里有2个点可以讨论:
- 先执行本地业务逻辑还是先通知下游接口,这2种顺序有什么不同
- 系统之间的调用的异常可以避免吗
执行顺序问题
-
假如先通知下游接口,然后再执行本地业务逻辑
-
通知下游接口成功,本地业务逻辑执行失败的:这里需要重试保障本地业务逻辑成功
-
通知下游接口失败,本地业务逻辑不执行的:无影响,需要整体发起重试。
-
-
假如先执行本地业务逻辑,然后再先通知下游接口
-
执行本地业务逻辑成功,通知下游失败:需要重试通知下游接口。
-
执行本地业务逻辑失败,不执行通知下游接口:需要整体发起重试。
-
虽然上述2种情况看起来差不多:但是仔细想一下,先通知下游接口,再执行本地业务逻辑,会导致本地业务逻辑严重依赖下游接口,尤其是遇到网络不稳定的情况下,导致本地业务逻辑稳定性差以及消息处理积压。还有一方面就是本地业务如果出现了重试也无法解决的情况,会导致严重的业务数据不一致,如果要求下游系统去修数回滚,这本身就比较扯。
因此推荐先执行本地业务逻辑,然后再先通知下游接口。
系统之间的调用的异常可以避免吗
由于网络因素的存在,所以系统之间的调用的异常是无法避免的,因此还需要有配套的兜底重试方案处理这种异常。
虽然重试比较简单,但真正有效的重试需要区分网络问题导致的系统异常还是业务异常,如果是业务异常这种情况重试方案意义不是很大,此时可能更需要人工介入,如果是网络问题导致的异常此时的兜底重试很有意义。
因此上述完整的解决方案应该是:
1.先执行本地业务逻辑,然后再先通知下游接口
2.增加配套重试补偿机制
总结
服务间调用看似简单,实则暗藏玄机。通过调整执行顺序、优化性能、设计重试机制,我们不仅能避免数据不一致,还能提升系统的稳定性。
你在项目中遇到过类似问题吗?欢迎在评论区分享你的解决方案!
关注公众号:【架构之门】,相遇即是缘,如果学到了知识,记得关注下奥😊,防止下次迷路