使用内置的Node.js分析器

170 阅读5分钟

开始作为一个软件开发者,建议遵循一个更务实的方法来开发软件。

随着时间的推移,当你开始建立更复杂的软件,为成千上万的用户提供服务时,更加关注架构、系统设计、测试、安全、部署等概念,尤其是性能,就变得至关重要。此外,在性能方面,通常的做法是关注关键的性能指标,如平均响应时间、流量率、以及你的应用程序和服务器的CPU使用率。

现在的主要问题是获得最好的剖析器工具,根据这些指标来衡量你的Node.js应用程序的性能,并且不影响软件的响应能力。

Windows Task Manager Meme

注意,CPU剖析和CPU监控经常被交替使用,但它们是不同的。

在这篇文章中,你将了解到Node.js中推荐的内置剖析工具。

为什么要进行剖析?

剖析是收集和分析你的代码中的函数在执行时的表现的数据,关于性能测量参数,如时间复杂性、吞吐量、输入工作负载、垃圾收集以及调用和执行一个函数的时间。

这里的目的是为了确定你的代码中的瓶颈。瓶颈发生在某行/块代码或函数的性能不如程序的其他部分时。其中一些瓶颈可能很明显,但大多数并不明显。

因此,从本质上讲,剖析器告诉你,"嘿,不要紧张,猜测使你的应用程序变慢的错误隐藏在哪里。让我来帮助你以编程方式完成这个任务。"

Node.js剖析器

在Node.js中,对应用程序进行剖析的最简单方法是使用内置的剖析器,它从函数中收集所有数据并将其记录到一个文件中。Node.js通过引入--prof 标志来实现这一点,它与V8分析器进行通信,然后记录数据。

让我们用一个Node.js应用的例子来说明这一点。这个例子使用了Node.js框架Fastify。Fastify声称是 "城里最快的网络框架!"所以我觉得用它来做演示是最合适的。

Fastify的API为一个书店应用程序执行CRUD操作。要跟上进度,你可以克隆GitHub repo

让我们研究一下controllers/bookController.js 中的处理函数,并对它们进行剖析。

//controllers/bookController.js

const boom = require('boom')
const Book = require('../models/Book')

// get all books
exports.getAllBooks = async (req, reply) => {
  try {
    const books = await Book.find()
    return reply.code(200)
    .send(
        {
         Message: "Success",
         data: books
        }
    )
  } catch (err) {
    throw boom.boomify(err)
  }
}

// get a single book by id
exports.getSingleBook = async (req, reply) => {
  try {
    const id = req.params.id
    const book = await Book.findById(id)

    return reply.code(200)
      .send({
        Message: "Success",
        data: book
      })
  } catch (err) {
    throw boom.boomify(err)
  }
}

// add a new book
exports.addNewBook = async (req, reply) => {
  try {
    const book = new Book(req.body)
    const newBook = await book.save()

    return reply.code(200)
      .send({
        Message: "New Book added successfully",
        data: newBook
      })
  }
    catch (err) {
      throw boom.boomify(err)
    }
}

// edit a book
exports.updateBook = async (req, reply) => {
  try {
    const id = req.params.id
    const updatedBook = await Book.findByIdAndUpdate(id, req.body, {
      new: true
    })

    return reply.code(200)
      .send({
        Message: "Book updated successfully",
        data: updatedBook
      })
  } catch (err) {
    throw boom.boomify(err)
  }
}

// delete a book
exports.deleteBook = async (req, reply) => {
  try {
    const id = req.params.id
    const deletedBook = await Book.findByIdAndDelete(id);

    return reply.code(200)
      .send({
        Message: `${deletedBook.title} has been deleted successfully`,
        data: id
      })
  } catch (err) {
    throw boom.boomify(err)
  }
}

你可以像这样向MongoDB添加一些数据。

> db.user.insert({ title: "The book for old people", genre: "Self Help" })

我们正在添加一些数据,以帮助我们模拟用户在向你的应用程序发出请求时出现延迟问题的场景。所以你可以继续在数据库中创建尽可能多的数据。

在你的终端上运行这个命令。

node --prof controllers/bookController.js

这个命令会创建一个isolate-0xnnnnnnnnn-v8.log (其中n是数字)的日志文件,它应该是这样的。

Fastify API Log File

无法阅读,对吗?这就是为什么我们要运行--prof-process 标志,将该日志文件转换为一个更可读的文件。

在你的终端上运行这个命令。

node --prof-process isolate-000001EFE5017350-7076-v8.log > processed.txt

这将创建一个包含日志的processed.txt 文件。

让我们检查一下这些日志,从摘要部分开始。

Fastify API Log Summary

这表明收集到的97%的样本都是从共享库中获得的。因此,让我们把重点放在[共享库]部分,而忽略其他部分。

Fastify API Log Shared Libraries

我们可以看到,89%的CPU时间被Node.js运行环境占用,8%被Windows内核函数占用。另外,它清楚地表明,在你的本地开发服务器上进行代码剖析并不理想。从HTTP服务器上运行测试是比较好的。所以,让我们用Ngrok模拟一个生产环境。

Ngrok使你能够创建公共的URL来暴露你的开发网络服务器。你可以在这里学习如何设置Ngrok

一个典型的Ngrok URL看起来像 [http://873acd0acf28.ngrok.io](http://873acd0acf28.ngrok.io).

现在我们不再依赖Node.js运行时和操作系统内核来运行我们的Node服务器。我们将再次运行--prof 属性。首先,给服务器添加一些负载。我使用Postman作为API客户端来测试我的API端点,但你可以使用任何你想要的工具。

Postman Test of API Endpoints

你可以继续添加更多的书。

Add Books to Your Fastify API

让我们也用Apache的基准测试工具得到AB的输出。如果你不知道如何安装这个工具,我在下面的资源部分丢了一个链接。

AB的输出。

Apache Benchmarking Output

值得注意的是,在我们这个简单的例子中,每个请求(无论成功与否)平均在3秒内完成一次往返,每秒钟提供大约4个请求。在一个真实世界的应用中,你会想出一些策略来改善这些数字,这样当流量上升时,用户就不会对你的应用响应能力产生问题。

到目前为止,这很好。现在,让我们重新运行--prof-process 命令并尝试分析报告。

在你的终端上运行以下命令。

NODE_ENV=production node --prof index.js

node --prof-process isolate-000001E540DA5730-19636-v8.log

在这一点上,你应该能够阅读、分析,并在有任何瓶颈的情况下实施解决方案。

结论

内置的Node.js剖析器是最简单和最适合剖析你的Node.js应用程序。在这篇文章中,我们讨论了为什么剖析很重要,以及如何使用--prof--prof-process 标志来调试瓶颈。

我希望你在阅读过程中能学到一些新东西。如果你有问题或建议,请在评论区提出来。

The postUsing the inbuilt Node.js profilerappeared first onLogRocket Blog.