起因
昨天压测某品牌网站首页,效果非常不理想:
ab 参数:数量 -n 1000,并发 -c 100
指标 | 结果 |
---|---|
每秒请求数(个/秒) | 5.95 |
单个请求平均用时(ms) | 168ms |
50% 以上请求用时(s) | 16-28 |
分析
由于首页接口调用繁重,定位问题有些“困难”,一步步看吧:
1 | // 首页 |
先排除首页内部第三方服务接口的瓶颈
首页需支持 SEO,做了服务端渲染,并且至少 5 次会调用第三方 api。但这些接口用 ab 比较难制定,用 node 专门写了个测试 api 组合的压测,ab 结果如下:
指标 | 结果 |
---|---|
每秒请求数(个/秒) | 88.02 |
单个请求平均用时(ms) | 11.361 |
50% 以上请求用时(s) | 0.9-8s |
由于这些第三方服务数据量虽然重,但之前已经做过缓存优化。从结果可以发现并不是瓶颈的主要原因。
排除自身服务接口影响
内部服务采用 java,首页对其依赖很少,数据也很轻量。
拿了一个主要接口做测试,结果很理想:
指标 | 结果 |
---|---|
每秒请求数(个/秒) | 569.12 |
单个请求平均用时(ms) | 1.757 |
50% 以上请求用时(s) | 0.1-0.7 |
node 非模板接口
找了一个 非模板渲染 的接口,做压测:
指标 | 结果 |
---|---|
每秒请求数(个/秒) | 1347.95 |
单个请求平均用时(ms) | 0.742 |
50% 以上请求用时(s) | 0.07-0.09 |
结果甚至比 java 服务还要优秀,符合 node 本身的事务处理能力
最终定位到 node 渲染层
对比之下,首页就多了 render 页面渲染功能。果断打开 express 模板缓存。
1 | app.set('views', path.join(__dirname, 'views')); |
对比之前未打开缓存,结果如下:
指标 | 结果 |
---|---|
每秒请求数(个/秒) | 92.68 vs 5.95 |
单个请求平均用时(ms) | 10.790 vs 168 |
50% 以上请求用时(s) | 0.68-3 vs 16-28 |
可以发现性能 大幅提升,元凶找到。
具体缓存实现,参见附录。
附录(express cache 原理)
express 在启动时,会初始化 render options
1 | app.set('view cache', true); |
express 通过 View 对视图做解析,根据 ext 来选择指定模板引擎,同时第三方模板库会暴露一个 __express 供 express 此处调用。
1 | function View(name, options) { |
1 | // pug express 扩展 |
打开 express ‘view cache’ 后,每次模板调用就会事先到缓存中命中,免去文件 io 的损耗和解析。
1 | // pug 模板缓存 |