由一次Content download超时引发的探索
各个浏览器都有对网络包在整个请求链路任意阶段的计时日志,这个功能能够帮助我们先大致定位一个请求超时的原因范围。以下是尝试复现一些可能存在的问题,以及提出一些解决方案
实验的工具:
- 服务器:阿里云ECS 一个CPU最差、内存最小、带宽最小的版本,用来模拟并暴露各个生产环境可能存在的瓶颈
- 数据库:阿里云RDS mySQL
- 后端:java + SpringBoot 快速构建测试服务
- 浏览器:Chrome
场景1:content download时间过长
这个问题的背景是:实习的过程中前端有一个请求是要查找数据库中埋点数据相关的信息,于是尝试在一个请求将id,url,property,details等信息全量查询出来,再在前端筛选或者完成计算;问题是这些信息中有个字段的内容是json,还是个不小的json,导致单行数据量就比常规MySQL数据大很多;于是当表中行越来越多,内容下载的时间必然越来越大
这个时间具体和哪些因素有关?
- 数据量
- 带宽
- 网络
以下是对这三个可能的瓶颈分别进行测试:
- 数据量太大:
数据库中我存储了1000行数据,每个含有一个json字段(在MySQL中使用String类型,而不是json类型),查询时将这些json都全量查询,总计1.1MB
SQL:
查询结果:
正常数据量的查询:
由此可见:当数据量从250B扩展到1.1MB,扩展4000倍后,内容下载从1ms扩展至7000ms,翻了7000倍;说明数据量的影响还是很大的
那解决的方式有哪些呢?
-
后端减少无效字段,或者将数据分成多个接口,让前端根据重要性依次加载
-
数据压缩,http协议中声明gzip压缩
http accept-encoding详解 HTTP协议-压缩(gzip,deflate)-CSDN博客
http传输图片,音频都需要压缩后传输,那对于超大文本文件自然也可以使用,博客中分析到一般gzip协议能够压缩60%的空间,感觉还是能起点用的
nginx配置gzip压缩,优化传输效率,加快页面访问速度_nginx gzip-CSDN博客
这篇文章大佬分享了在网关中压缩response,说明这个策略的解决方案普遍适用
-
更高的带宽、更稳定的网络...
带宽方面:除了直接升级网卡外,网上还有其他思路
这种使用类似集群的方式负载均衡
- 联系运营商提高带宽
补充说明:我用本地Tomcat运行服务器,执行相同数据量相同代码的测试,结果是正常的,只有几百ms的RT,说明比数据量更关键的其实是带宽。我使用的阿里云ECS配置如下
可以说是拉中之拉,而本地运行的带宽受网卡和运营商的影响,我查到的我的笔记本的带宽至少都有100Mb;所以看起来似乎很难在带宽上出现瓶颈。
- 带宽太小:
我的测试方案是:在原本带宽就很小的ECS上,通过占用大量带宽来模拟出现瓶颈的场景,而如何占用大量带宽呢?我在Tomcat中部署了一个1280 * 590的视频,在请求视频资源时测试正常请求下载内容的时间变化
- 没有请求视频资源:
- 请求视频资源的同时:
时间只是翻倍,似乎效果并不显著,接下来我让数据量再增大很多,理论上数据量很大的情况下很能体现带宽不足的情况
- 没有请求视频资源:
- 请求视频资源的同时:
并且由于时间拉长,很明显观察到当这个请求发起时,视频出现卡顿,也就是视频的请求的内容下载所使用的带宽不足了
过程记录:
- 网络问题:
参考一篇大佬的博客,可以很具体的分析出网络链路上哪里阻碍了内容下载: 对HTTP请求接口资源下载时间过长的问题分析 - lulianqi15 - 博客园 (cnblogs.com)
场景2:TTFB 等待第一个字节响应的时间太长
网上很多关于TTFB时间长的分析都是基于早期模板引擎语言如php,jsp,所分析的“第一个字节”是指html的第一个字节,而这里分析的是一般的基于JSON的请求响应数据包。
相关博客(PHP) 解决网页响应慢,waiting(TTFB)时间过长_waiting(ttfb)-CSDN博客
TTFB有三个部分组成:
- 浏览器发出请求,通过网络到达服务器的时间
- 服务器处理请求所花费的时间
- 服务器将响应的第一个字节发送回浏览器所花费的时间
其中,1,3受限于网络状况;2取决于请求在后端整个链路的耗时
1,3可能需要更高级的技术分析TCP报文的阻塞,重试等耗时的优化实践,暂时在网上没有找到相关内容;下一步可能需要探索使用【Wireshark】 + Chrome的【Capture Network Log】详细分析每个报文的日志,思路来源于博客:
对HTTP请求接口资源下载时间过长的问题分析 - lulianqi15 - 博客园 (cnblogs.com)
对于第二种情况的测试:
test接口:
blockTest接口:
说明后端的耗时最直接的影响TTFB,而后端的架构与逻辑可以很复杂,这就导致判断TTFB到底在后端哪一步有不正常的耗时需要更仔细的观测
-
单机架构
问题可能是:
- Tomcat线程池有限,请求在阻塞队列中排队
- 解决思路:有一招开源组件DynamicTp可以操作Tomcat的线程池,从而扩展最大线程数 首页 | dynamictp
- myBatis使用UNPOOLED,同时并发的请求有很多,导致无法建立新连接的过程,只能等待某些资源
- 数据库响应较慢,这其中更是情况很多,我暂时能想到的比如连接池设置不合理,需要读写分离,SQL查询太慢...
-
引入本地缓存 + 分布式缓存
问题可能出现在:
-
缓存过期
-
redis碰巧在进行RDB持久化?或者正在进行哨兵选主?(盲猜)
希望有大佬点明有没有可能性
-
反向代理,负载均衡
问题可能出现在:
-
Nginx对后端的请求存在超时机制,如果超时时间设置太短,附加重试机制而非返回错误信息,可能会导致后端执行不完,但却一直在执行 Nginx的超时timeout配置详解 - 细水流深-LHF的博客 - 博客园 (cnblogs.com)
-
其他更复杂的架构...
场景3:stalled 阻塞时间太长
转载自:https://juejin.cn/post/7368052129904918569