在我所在的团队Node主要是用于提供接口数据和页面渲染。既然文章标题是和node接口耗时相关的,我先讲一下我们node是如何做接口数据提供的。
前端页面要想拿到数据,主要会经历三层,node->后端->核心数据。这三层都是属于内网调用,互相之间各有nginx进行调度。
所以从以上三层结构来看,想要提升node接口耗时,就是对内(node自身)处理逻辑和对外(后端及核心数据)交互过程进行优化。
由于node是单线程模型,所以优化更多的是要减少io操作,减少同步阻塞,避免执行CPU密集型操作,以下是我所使用的一些优化方法。
1. 将串行网络请求改为并行网络请求,这一点非常重要,但有时候也容易被忽略,将网络请求改为并行之后会发现接口耗时下降明显。
// 串行
let test = async () => {
let res1 = await request(url1);
let res2 = await request(url2);
return [res1, res2];
};
// 并行
let test = async () => {
let res = await Promise.all([
request(url1),
request(url2)
]);
return res;
};
2. 请求后端数据时采用持久连接
// 以下是axios的例子
let http = require('http');
let httpAgent = new http.Agent({keepAlive: true});
let axios = require('axios');
axios({httpAgent}).then(/******/).catch(/******/);
3. 避免与后端做重复工作。由于历史原因,当初团队建立node项目迁移接口时会参考以前后端同学的代码,故而导致一些代码逻辑里面做了与后端同学一样的重复工作。从我们项目来看,发现比较多的情况是在node和后端都调用了公司登录校验的接口,在node层去掉一次校验之后,耗时大概下降了5-6ms。
4. node直连核心数据。在与后端同学沟通过程中发现一些接口在他们那边并没有逻辑处理,完全是透传的过程,所以决定重写node网络请求模块,使其支持node直连核心数据的方式,减少一层网络请求的过程,由原来的三层结构变为两层,经过处理后的接口耗时平均下降了8ms。
5. 使用调试工具查找node运行时耗时比较高的操作
–inspect
参数(inspect
前面是两根横杠)chrome://inspect
,可以看到如下的页面,然后点击红色箭头处的inspect
,弹出调试页面。Profiler
,点击start经过以上步骤我们可以逐步找到代码中比较耗时的操作,然后可以查看代码逻辑进行针对性的优化,优化一些CPU密集型操作的代码,比如使用fast-json-stringify
替代JSON.stringify()
。
6. 对不会频繁变动的接口数据进行缓存。在我们的项目里面有两种缓存方式,一种是将数据存储在机器内存里面,另一种是存储在redis中。我们分别使用的是memory-cache和ioredis工具包,如需使用,可参考官方文档。
7. 升级node版本。node项目在第一次线上部署之后,版本就处于7.10.0一直没更换过;根据官网的benchmark(https://benchmarking.nodejs.org/)来看,node版本的升级还是会带来比较大的性能提升,因为7.10.0版本确实属于比较老的版本了。以下是我的升级过程:
pm2 save
pm2 kill
pm2 resurrect
以上便是目前我对于降低node接口耗时所使用的一些小小的办法,如果你还有一些更好的想法和思考,欢迎联系我,一起交流学习。