本文源于mp.weixin.qq.com/s/_1pZ8ShmE… 作者:潘新宇
关注公众号:勾勾的Java宇宙(Javagogo)
完成一个写请求时,不仅需要依赖存储,大部分场景还需要依赖各种外部第三方提供的接口。
-
当你发布一条微博,在数据存储至数据库前,不仅需要依赖用户模块校验用户的有效性,还需要依赖安全过滤非法内容等;
-
在创建订单时,同样是先要校验用户有效性、再校验用户的收货地址合法性,以及获取最新价格、扣减库存、扣减支付金额等。完成上述的校验和数据获取,最后一步才是写入存储。
-
其他的写场景,比如发布短视频、发布博客等亦是如此。
上述几种场景的架构如下图所示:
对于整个链路依赖的各项外部接口,可能是出现了以下几个问题,导致系统不可用:
- 外部接口性能抖动严重,比如从 50ms 飙升至 500 ms,进而导致你的接口超时,此时会影响你的系统可用率
- 完成上述某一个写业务时,如果需要依赖外部的接口过多,也会导致你的接口性能太差
- 外部接口可用率下降,也会影响你的系统的可用率
当依赖外部接口过多时,可以从几个方面进行优化,来提升整体的性能和写接口的稳定性。
将依赖接口串行改并行
假设一次写请求要依赖二十个外部接口,可以将这些依赖全部并行化,优化的架构如下图所示:
如果一个依赖接口的性能为 10ms,以串行执行的方式,请求完所有外部依赖就需要 200ms(10ms×20)。但改为并行执行后,只需要 10ms 即可完成。
上述情况中,我们假设每个接口的性能都是 10ms,但在实际场景中并没有这么精确的数字,有的外部依赖可能快一点、有的可能慢一点。实际并行执行的耗时,等于最慢的那个接口的性能。
全部外部依赖的接口都可以并行是一种理想情况。
接口能否并行执行有一个前置条件:两个接口间没有任何依赖关系。
如果 A 接口执行的前置条件是需要 B 接口返回的数据才能执行,那么这两个接口则不能并行执行。按相互依赖梳理后的并行执行方案如下图所示。对于并行中存在相互依赖的场景,并行化后的性能等于最长子串(下图中红色框)的性能总和。
依赖接口后置化
此外,虽然整个链路上会有较多外部接口,但大部分场景里,很多接口都是可以后置化的。后置化是指当接口里的业务流程处理完成并返回给用户之后,后置去处理一些非重要且对实时性无要求的场景。
比如在提交订单后,用户只需要查看订单是否下单成功,以及对应的价格、商品和数量是否正确。而对于商品的详细描述信息、所归属的商家名称等信息并不会特别关心,如果在提单的同时还需要获取这些用户不太关心的信息,会给整个提单的性能和可用率带来非常大的影响。
鉴于这种情况,可以在提单后异步补齐这些仅供展示的信息。
采用依赖后置化后,需要增加一个异步 Worker 进行数据补齐。架构如下图所示:
对于一些可以后置补齐的数据,可以在写请求完成时将原始数据写入一张任务表。然后启动一个异步 Worker,异步 Worker 再调用后置化的接口去补齐数据,以及执行相应的后置流程(比如发送 MQ 等)。
通过依赖后置化移除一些不必要的接口调用,会提升你的写接口的整体性能和可用性。
本文源于mp.weixin.qq.com/s/_1pZ8ShmE… 作者:潘新宇
关注公众号:勾勾的Java宇宙(Javagogo)