背景
在公司参与了一个做度量统计的项目,该项目的特点是页面上的表格、卡片、图标非常多。项目经常出现一种情况:页面加载速度较慢,开始怀疑是由于计算量较大,后端接口相应速度较慢。优化了一版后端接口后(加缓存、优化SQL),发现有时接口的相应速度还是很慢,有的接口能达到3秒多,严重影响了用户体验。
问题排查
页面加载速度太慢,严重影响了用户体验,因此必须要解决这个问题。
开始的时候怀疑是后端接口问题,因此针对一些计算量确实很大的接口,对热点数据加了缓存。理论上来说,加了缓存后接口速度应该在100ms以内就可以返回,但是实际在页面上查看接口返回时间时,发现接口的返回时间有时还是会到3秒左右,这种情况就存在问题了。
针对单一接口,我使用postman发起调用,发现无法复现该问题,只有在前端页面上请求才会存在返回时间超过3秒的情况。因此,我们开始使用Chrome浏览器提供的工具查看这些耗时较多的接口(由于公司数据不可外泄,因此在博客里面我就直接使用公开的报表页面进行排查演示)。
从该页面中选取了一个接口进行测试,点击Chrome浏览器的调试按钮,查看网络面板中的时间数据,整个接口的耗时如上图所示。
简单解释一下:该接口整体的响应时间为281.47ms,其中Stalled时间占用了169.84ms的时间,获取后端接口数据的时间为111.63ms。其中,111.63ms可以理解为后端接口的真实响应时间,但是stalled的这段时间是干什么的呢?这一阶段的耗时比后端接口返回数据的时间还要长。
对Chrome发起的网络请求进行抓包,具体操作如下:
- 进入chrome://net-export/网页点击开始调试
- 重新请求该报表页面
- 停止抓包,保存日志文件
- 进入https://netlog-viewer.appspot.com/#import网页,导入抓包日志,对抓包日志进行可视化分析,结果如下图所示
点击最上侧的搜索框,可以按照接口URL进行搜索,搜索排查后发现接口是在
HTTP_STREAM_REQUEST_BOUND_TO_JOB阶段耗时过多,再进一步查看,发现是接口在等待复用套接字。
到这里,我们就知道为什么前端页面上的接口相应时间过长了,主要时间都耗费在等待复用套接字上了,那为什么会在这个地方进行等待呢,是因为HTTP1.1限制了在Chrome浏览器下对同一个域名的并发请求最大是6,当超过6个时,就得排队等待前面的请求数据返回释放套接字后才能进行请求。
问题解决
查明了问题,那如何解决这个问题呢?
两个办法:一个是由于HTTP1.1是对单个域名限制了并发请求数,那我们可以同时对多个域名进行请求来避免阻塞;另一个是升级HTTP协议,将HTTP协议升级到HTTP2.0,HTTP2.0由于多路复用的特性,不再限制并发请求数(需注意对后端系统的负载影响,同时并发请求会对后端系统造成更大的负载,还需注意客户端对HTTP2.0协议的兼容性,如果不兼容的话,即使开启了HTTP2.0,也会退化到HTTP1.1的)。
综合多种考虑,结合公司里关于HTTP2.0的故障反馈,确认对我们的系统无影响后,我们决定升级HTTP协议来解决该问题,先在测试环境开启,测试几天后,在线上环境灰度开启,最终全部开启。
注意,HTTP2.0协议强依赖于HTTPS协议,需确保服务首先支持HTTPS协议!