热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何优化你的Node.jsAPI

大厂技术高级前端Node进阶点击上方程序员成长指北,关注公众号回复1,加入高级Node交流群在这篇文章中,我将讲解如何优化使用Node.j

da84121e0e117854a5d24ee9b9c16d2b.jpeg

大厂技术  高级前端  Node进阶

点击上方 程序员成长指北,关注公众号

回复1,加入高级Node交流群

在这篇文章中,我将讲解如何优化使用 Node.js 编写的 API。

前提条件

想要充分了解本文内容,你必须了解以下概念:

  • Node.js 的设置与安装

  • 如何使用 Node 创建 API

  • 如何使用 Postman

  • Javascript 的 async/await 工作原理

  • Redis 的基础操作

API 优化到底指的是什么

优化包含了改善 API 的响应时间。响应时间越短,API 的速度越快。

我将在本文分享一些技巧,帮助你缩短响应时间、降低延迟、管理错误和吞吐量,并且最大限度地减少 CPU 和内存的使用

如何优化 Node.js 的 API

1. 始终使用异步函数

异步函数就像 Javascript 的心脏。因此,优化 CPU 使用率的最佳方法就是编写异步函数来执行非阻塞 I/O 操作。

I/O 操作包括对数据的读和写。它可以在数据库、云存储或者任何本地磁盘上进行。

在大量使用 I/O 操作的应用使用异步函数可以提高效率。因为由于没有阻塞 I/O,当一个请求在做输入/输出操作的时候,CPU 可以同时处理多个请求。

举例如下:

var fs = require('fs');
// 执行阻塞I/O
var file = fs.readFileSync('/etc/passwd');
console.log(file);
// 执行非阻塞I/O
fs.readFile('/etc/passwd', function(err, file) {if (err) return err;console.log(file);
});

  • 使用 Node 包 fs 来处理文件

  • readFileSync() 是同步函数,会在执行完成前阻塞线程

  • readFile() 是异步函数,会立刻返回并在后台运行

2. 避免在 API 中使用 session 和 COOKIE,仅在 API 响应中发送数据

当我们使用 COOKIE 或者 session 来存储临时状态的时候,会占用非常多的服务器内存。

现在通用无状态 API,并且也有 JWT、OAuth 等验证机制。验证令牌保存在客户端以便服务器管理状态。

JWT 是基于 JSON 的用于 API 验证的安全令牌。JWT 可以被看到,但一旦发送就无法修改。JWT 只是一个序列并没有加密。OAuth 不是 API 或服务——相反,它是授权的开放标准。OAuth 是一组用于获取令牌的标准步骤。

同时,也不要把时间浪费在使用 Node.js 来服务静态文件。这方面 NGINX 和 Apache 做得更好。

使用 Node 搭建 API 的时候,不要在响应中发送完整的 HTML 页面。当仅有数据通过 API 发送的时候,Node 服务得会更好。大部分 Node 应用都使用 JSON 数据。

3. 优化数据库查询

优化 Node API 的重要一环是优化查询。特别是对于大型应用来说,我们需要多次查询数据库,所以一个糟糕的查询会降低应用的整体性能。

索引是一种优化数据库性能的方法,通过最小化处理查询时所需的磁盘访问次数来实现。它是一种数据结构技术,用于快速定位和访问数据库中的数据。索引是使用几个数据库列创建的。

假设我们有一个没有索引的数据库模式,并且数据库包含 100 万条记录。与带有索引的模式相比,使用没有索引的模式做一个简单的 find(查找)查询将扫描更多的记录来找到匹配的记录。

  • 没有索引的查询

> db.user.find({email: 'ofan@skyshi.com'}).explain("executionStats")

  • 有索引的查询

> db.getCollection("user").createIndex({ "email": 1 }, { "name": "email_1", "unique": true })
{"createdCollectionAutomatically" : false,"numIndexesBefore" : 1,"numIndexesAfter" : 2,"ok" : 1
}

两者之间扫描文件的数量相差巨大 ~ 1038:

方法扫描文件
没有索引1039
有索引1

4. 使用 PM2 集群模式优化 API

PM2 是为 Node.js 应用程序设计的生产流程管理器。它内置了负载平衡器,允许应用程序在不修改代码的情况下,作为多个进程运行。

使用 PM2 时的应用停机时间几乎为零。总体来说,PM2 确实可以提升 API 性能和并发性。

在生产环境中部署代码并运行以下命令以查看 PM2 集群如何在所有可用 CPU 上进行扩展:

pm2 start  app.js -i 0

5. 减少 TTFB(第一字节时间)

第一字节时间是一种测量方式,用作表示 Web 服务器或者其他网络资源的响应时间。TTFB 测量从用户或客户发出 HTTP 请求到客户的浏览器收到页面的第一个字节的时间。

所有用户访问浏览器的同一页面加载速度不可能在 100 毫秒之内,这仅仅是因为服务器和用户之间的物理距离。

我们可以通过使用 CDN 和全球本地数据中心缓存内容来减少第一个字节的时间。这有助于用户以最小的延迟访问内容。你可以从 Cloudflare 提供的 CDN 解决方案开始着手。

6. 使用带日志的错误脚本

监视 API 是否正常工作最好的办法是记录行为,于是记录日志就派上用场。

一个常见的办法是将记录打印在控制台上(使用console.log())。

console.log()更高效的方法是使用 Morgan、Buyan 和 Winston。我将在这里以 Winston 为例。

如何使用 Winston 记录 – 功能

  • 支持 4 个可以自由选择的日志等级,如:info、error、verbose、debug、silly 和 warn

  • 支持查询日志

  • 简单的分析

  • 可以使用相同的类型进行多个 transports 输出

  • 捕获并记录 uncaughtException

可以使用以下命令行设置 Winston:

npm install winston --save

这里是使用 Winston 记录的基本配置:

const winston = require('winston');let logger = new winston.Logger({transports: [new winston.transports.File({level: 'verbose',timestamp: new Date(),filename: 'filelog-verbose.log',json: false,}),new winston.transports.File({level: 'error',timestamp: new Date(),filename: 'filelog-error.log',json: false,})]
});logger.stream = {write: function(message, encoding) {logger.info(message);}
};

7. 使用 HTTP/2 而不是 HTTP

除了上述使用的这些技巧,我们还可以使用 HTTP/2 而不是 HTTP,因为它具备以下优势:

  • 多路复用

  • 头部压缩

  • 服务器推送

  • 二进制格式

它专注提高性能,并解决 HTTP 的问题。它使网页浏览更快、更容易,并且消耗更少的带宽。

8. 并行任务

使用 async.js 来运行任务。并行任务对 API 的性能有很大改善,它减少了延迟并最大限度地减少了阻塞操作。

并行意味着同时运行多个任务。当你并行任务的时候,不需要控制程序的执行顺序。

以下是一个数组异步并行的简单例子:

const async = require("async");
// 使用对象而不是数组
async.parallel({task1: function(callback) {setTimeout(function() {console.log('Task One');callback(null, 1);}, 200);},task2: function(callback) {setTimeout(function() {console.log('Task Two');callback(null, 2);}, 100);}
}, function(err, results) {console.log(results);// 结果相当于: {task2: 2, task1: 1}
});

在以上例子中,我们使用了 async.js 以异步的形式执行了两个任务。task 1 需要 200 毫秒完成,但是 task 2 不需要等待 task 1 完成后再执行 – 它在设定的 100 毫秒后执行。

并行任务对 API 的性能有很大的影响。它减少了延迟并最大限度地减少了阻塞操作。

9. 使用 Redis 缓存应用

Redis 是 Memcached 的高级版本。它通过在服务器的主内存中存储和检索数据来优化 API 响应时间。它提高了数据库查询的性能,也减少了访问延迟。

在下面的代码片段中,我们分别调用了不使用 Redis 和使用 Redis 的 API,并比较了响应时间。

响应时间差异巨大~ 899.37 毫秒:

方法响应时间
不使用 Redis900ms
使用 Redis0.621ms

以下是不使用 Redis 的 Node:

'use strict';//定义需要的所有依赖项
const express = require('express');
const responseTime = require('response-time')
const axios = require('axios');//加载 Express 框架
var app = express();//创建在响应头中添加 X-Response-Time 的中间件
app.use(responseTime());const getBook = (req, res) => {let isbn = req.query.isbn;let url = `https://www.googleapis.com/books/v1/volumes?q=isbn:${isbn}`;axios.get(url).then(response => {let book = response.data.itemsres.send(book);}).catch(err => {res.send('The book you are looking for is not found !!!');});
};app.get('/book', getBook);app.listen(3000, function() {console.log('Your node is running on port 3000 !!!')
});

以下是使用 Redis 的 Node:

'use strict';//定义需要的所有依赖项
const express = require('express');
const responseTime = require('response-time')
const axios = require('axios');
const redis = require('redis');
const client = redis.createClient();//加载 Express 框架
var app = express();//创建在响应头中添加 X-Response-Time 的中间件
app.use(responseTime());const getBook = (req, res) => {let isbn = req.query.isbn;let url = `https://www.googleapis.com/books/v1/volumes?q=isbn:${isbn}`;return axios.get(url).then(response => {let book = response.data.items;//设置string-key:缓存中的 isbn。以及缓存的内容: title// 设置缓存的过期时间为 1 个小时(60分钟)client.setex(isbn, 3600, JSON.stringify(book));res.send(book);}).catch(err => {res.send('The book you are looking for is not found !!!');});
};const getCache = (req, res) => {let isbn = req.query.isbn;//对照服务器的 redis 检查缓存数据client.get(isbn, (err, result) => {if (result) {res.send(result);} else {getBook(req, res);}});
}
app.get('/book', getCache);app.listen(3000, function() {console.log('Your node is running on port 3000 !!!')
)};

总结

在本指南中,我们了解了如何优化 Node.js API 的响应时间。

Javascript 重度依赖函数,因此,使用异步函数可以使脚本运行得更快并且不阻塞。

除此之外,我们还可以使用缓存记忆(Redis)、数据库索引、TTFB 和 PM2 集群来提高响应速度。

最后请记住,注意路由的安全性并尽可能优化路由也很重要。我们不能为了提高 API 响应速度而妥协掉安全性。因此,在 Node.js 中构建优化的 API 时,应该保留所有标准安全检查。

Happy coding!

Node 社群我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。如果你觉得这篇内容对你有帮助,我想请你帮我2个小忙:1. 点个「在看」,让更多人也能看到这篇文章2. 订阅官方博客 www.inode.club 让我们一起成长点赞和在看就是最大的支持❤️


推荐阅读
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了2019年上半年内蒙古计算机软考考试的报名通知和考试时间。考试报名时间为3月1日至3月23日,考试时间为2019年5月25日。考试分为高级、中级和初级三个级别,涵盖了多个专业资格。报名采取网上报名和网上缴费的方式进行,报考人员可登录内蒙古人事考试信息网进行报名。详细内容请点击查看。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • RouterOS 5.16软路由安装图解教程
    本文介绍了如何安装RouterOS 5.16软路由系统,包括系统要求、安装步骤和登录方式。同时提供了详细的图解教程,方便读者进行操作。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
author-avatar
欣仪威侑扬芸_782
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有