页面请求的拆 Or 不拆

avatar
SE

一、背景

是日也,天朗气清,惠风和畅,宜搬砖!在熟悉新模块的时候,使用抓包工具看了下页面的请求,发现了疑点: 进入一个页面的时候,为什么获取同一类型的数据需要发起多个请求呢? 当然,具体的业务场景是不可描述的,但请求拆分这个话题是值得进行一番探究的。

二、问题

假设,下图是产品老板给的一个交互页面,它需要获取并显示A、B、C三个数据,作为新时代农名工的我们,需要怎么设计这个接口呢?

image.png

  • 我应该拆分A、B、C三个接口来返回数据吗?
  • 抛硬币来选择拆分行不行?
  • 拆分的话有什么好处呢?前端大佬会跟我battle吗?
  • 不拆分的话有没有什么依据呢?

三、分析

搬砖也应当做到知其然,且知其所以然,这里总结了一些常见的判断节点。

1.图解

image.png

重要:仅阐明大概的思路以供参考,实际情况还需根据实际业务来做出判断

2.数据加载的时机、触发点是否一致?

如果 Data A Data B Data C 在页面中的触发点和加载时机是不一致的,一般是不应该放到一起的,因为可能会查询获取出未来不一定会使用到的数据(数据预加载的情况不在此讨论),给服务端增加不必要的请求。
例如:在答题场景的时候,点击显示答错次数按钮时,才需要对错题次数(DataC)进行显示,这样 DataC 的加载时机和触发点跟 头像(DataA)、题目(DataB) 是不一致的,所以一般不应该合并为一个接口。 image.png

3.是否接受部分成功?

如果 Data A Data B Data C是相互独立存在的,那么这三个数据是应该使用三个接口来获取的,因为使用 Data A 不依赖 Data BData C ,那么当获取Data BData C的接口出现问题的时候,也不会影响到 Data A 的相关逻辑。
例如:在刷题场景中,页面中题目(Data B)的获取失败,不应该影响用户头像(Data A)的正常获取。 image.png

4.是否来自同一个数据源?

数据源指的是:可以通过单次请求获取到所需要的数据,可以是mysql查询请求,也可以是dubbo接口请求,还可以是三方开放平台的http请求等。

如果对同一个数据源的数据进行多次请求查询获取,可能会增加不必要的查询、增加不必要的连接等(当然也会存在单次请求时间过长需要切分的场景)。
例如,有一个页面需要展示 语文题目数量(Data A)、数学题目数量(Data B)、英语题目数量(Data C),而如果查询科目习题数量的dubbo接口是支持批量查询的,那一般情况下就没有必要去查3次,一次查出即可。 image.png

5.管控粒度是否单一?(待定)

管控粒度一般指的熔断、限流、替换实现方案等处理的最小单位。

如果粒度是有所细分的,那么接口也做细分的话会更容易进行管理,出现问题的时候也便于做出精细化的响应措施。
例如:批改一篇作文的时候,修辞手法识别结果(Data A)、错别字识别结果(Data B)、病句识别结果(Data C)分别来自不同的服务商,按维度拆分接口有利于我们管理这些维度, 当 修辞手法维度识别(Data A) 的服务需要降级或替换的时候,不会影响到 错别字识别结果(Data B) 和 病句识别结果(Data C) 的请求,直接重试 修辞手法识别(Data A) 请求即可。 image.png

6.从非业务角度分析:拆,还是不拆?

上边的介绍的判断节点是跟业务场景强相关的,那么,如果一直到最后,从业务上看这些数据的请求可以拆,也可以不拆的时候,我们就需要判断这两种选择会给客户端、服务带来哪些影响了。

四、方案比对

1.结论先行

  • split:拆分请求
  • combine:合并请求 | 客户端等待时间 | 逻辑实现复杂度 | 错误重试的成本 | 服务端的吞吐率 | | :-: | :-: | :-: | :-: | | split ≈ combine | split > combine | split < combine | split ? combine |

2.请求示意

请求拆分与请求合并的示意图: image.png 其中,合并请求在服务端处理的时候会用到一个线程池 image.png

3.客户端等待时间

从请求示意图我们可以发现,不管拆分请求,还是合并请求,请求其实都应该是并行处理的,都是以最耗时资源(Data C)的获取为客户端的等待时间,所以相差不远。

PS:为什不考虑串行请求呢?因为这牺牲的是用户的等待时间,一般来说是不建议的

4.逻辑实现复杂度

对于拆分的情况来说,需要单独去发起请求、处理返回结果、建立处理重试机制等,所以会稍微复杂一点;相反,如果不对请求进行拆分的话,只需要处理一个请求,逻辑简单不少。

5.错误重试的成本

如果拆分了请求,在某个数据获取失败时,只需要重新获取该数据即可,而如果不进行拆分,中间某个环节出现错误的时候,需要再次获取之前已经获取过的数据,成本是比较高的。

6.服务端的吞吐率

从示意图可以看到,合并请求在服务器处理的时候,需要用到一个内部线程池,而通常情况下,我们不会给这个内部线程池配置很大的线程数(一般就是跟cpu核心数相关,低于100),这样会出现一个现象是:(假设tomcat有2000条线程,内部线程池大小设置为100)

  • 在拆分请求的场景下,使用的资源是所有的tomcat线程,也就是2000个线程
  • 在不拆分的场景下,请求会在内部的线程池中进行排队,实际有效的线程资源数是100个 因此,除非将内部线程池的线程数设置得跟tomcat线程池相当,否则直接压测得出的吞吐率意义不大。

五、总结

在日常的搬砖实践中,请求是否应当进行拆分的最大因素还是取决于业务的,没有绝对正确合适的判定条件,都是需要权衡各个方面的因素来做出决定。那么各位老板们,你们的请求拆分合理了吗?