Node.js 应用程序的前 5 个性能指标

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

最后几篇文章介绍了应用程序性能管理 (APM),并确定了有效实施 APM 策略的挑战。本文以这些主题为基础,回顾了要捕获的五个顶级性能指标,以评估您的企业 Node.js 应用程序的健康状况。

这篇文章具体评论了以下内容:

  • 商业交易
  • 外部依赖
  • 事件循环
  • 内存泄漏
  • 应用拓扑

商业交易

业务事务提供对真实用户行为的洞察:它们捕获真实用户在与您的应用程序交互时所体验的实时性能。如上一篇文章所述,衡量业务事务的性能涉及全面捕获业务事务的响应时间以及衡量其组成层的响应时间。然后可以将这些响应时间与最能满足您的业务需求的基准进行比较,以确定是否正常。

如果您只想衡量应用程序的一个方面,我建议您衡量业务交易的行为。虽然容器指标可以提供大量信息并可以帮助您确定何时自动扩展您的环境,但您的业务交易决定了您的应用程序的性能。与其询问您的应用程序服务器的 CPU 使用率,不如询问您的用户是否能够完成他们的业务交易以及这些业务交易是否正常运行。

作为一个小背景,业务事务由它们的入口点标识,这是与启动业务事务的应用程序的交互。对于 Node.js 应用程序,这通常是 HTTP 请求。可能会有一些例外,例如 WebSocket 连接,在这种情况下,业务事务可能是您定义的代码中的一个间隔。在 Node.js 工作服务器的情况下,业务事务可能是 Node.js 应用程序执行的作业,它从队列服务器中获取。或者,您可以选择为基于 URL 参数的同一 Web 请求或基于其正文内容的服务调用定义多个入口点。关键是业务交易需要与对您的业务有意义的功能相关。

一旦确定了业务事务,就会在整个应用程序生态系统中衡量其性能。每个单独的业务交易的性能都根据其基准进行评估,以评估正常性。例如,我们可能会确定,如果业务事务的响应时间比该基线的平均响应时间慢两个标准差,则表明它的行为异常,如图 1 所示。

图 1 根据其基线评估 BT 响应时间

用于评估业务交易的基线在业务交易运行的那一小时内是一致的,但是业务交易正在被每个业务交易执行细化。例如,如果您选择了一个基线来将业务交易与一天中某个小时和一周中某天的平均响应时间进行比较,则在当前小时结束后,该小时内执行的所有业务交易都将被纳入基线下周。通过这种机制,应用程序可以随着时间的推移而发展,而无需丢弃和重建原始基线;您可以将其视为随时间移动的窗口。

总之,业务交易是最能反映用户体验的衡量标准,因此它们是要捕获的最重要指标。

外部依赖

外部依赖项可以有多种形式:依赖 Web 服务、遗留系统或数据库;外部依赖项是您的应用程序与之交互的系统。我们不一定能控制在外部依赖项内部运行的代码,但我们通常可以控制那些外部依赖项的配置,因此了解它们何时运行良好以及何时运行不良很重要。此外,我们需要能够区分应用程序中的问题和依赖项中的问题。

从业务交易的角度来看,我们可以将外部依赖性识别和度量为在它们自己的层中。有时我们需要配置监控解决方案来识别真正包装外部服务调用的方法,但对于常见的协议,如 HTTP,可以自动检测外部依赖。与业务交易及其组成的应用程序层类似,外部依赖行为应该是基线,响应时间应该根据这些基线进行评估。

业务事务为您提供应用程序性能的最佳整体视图,并可以帮助您对性能问题进行分类,但外部依赖项会以意想不到的方式显着影响您的应用程序,除非您正在观察它们。

您的 Node.js 应用程序可能正在使用后端数据库、缓存层,甚至可能是队列服务器,因为它将 CPU 密集型任务卸载到工作服务器上以在后台处理。无论您的 Node.js 应用程序与哪个后端接口,这些后端服务的延迟都可能会影响您的 Node.js 应用程序的性能,即使您以异步方式与它们接口也是如此。各种类型的退出调用可能包括:

  • SQL数据库
  • NoSQL 服务器
  • 内部网络服务
  • 外部第三方网络服务 API

无论您的 Node.js 应用程序如何与内部或外部的第三方应用程序通信,等待响应的延迟都可能会影响您的应用程序的性能和您的客户体验。如果您的通信可以帮助解决这些瓶颈,则测量和优化响应时间。

事件循环

为了了解围绕事件循环行为收集哪些指标,首先了解事件循环实际上是什么以及它如何潜在地影响您的应用程序性能会有所帮助。出于说明目的,您可以将事件循环视为在队列中执行代码的无限循环。对于无限循环中的每次迭代,事件循环都会执行一个同步代码块。 Node.js——是单线程和非阻塞的——然后将选择下一个代码块,或者滴答,在队列中等待,因为它继续执行更多的代码。尽管它是一个非阻塞模型,但可能被视为阻塞的各种事件包括:

  • 访问磁盘上的文件
  • 查询数据库
  • 从远程网络服务请求数据

使用 Javascript(Node.js 的语言),您可以利用回调的优势执行所有 I/O 操作。这提供了执行流继续执行其他代码的优势,而您的 I/O 在后台执行。 Node.js 将执行事件队列中等待的代码,在可用线程池中的线程上执行它,然后继续执行队列中的下一个代码。一旦您的代码完成,它就会返回并指示回调执行其他代码,因为它最终会完成整个事务。图 2 中的图表直观地解释了代码如何等待事件循环在队列中执行。

重要的是要注意,Node.js 的异步特性中的代码执行流不是按请求执行的,而在其他语言(如 PHP 或 Python)中可能是这样。换句话说,假设您有最终用户请求的两个事务 X 和 Y。

当 Node.js 开始执行来自事务 X 的代码时,它也在执行来自事务 Y 的代码,并且由于 Node.js 是异步的,来自事务 X 的代码与来自事务 Y 的代码在队列中合并。来自两个事务的代码本质上都在等待在等待事件循环同时执行的队列中。因此,如果事件循环被事务 X 的代码阻塞,则执行速度变慢可能会影响事务 Y 的性能。

Node.js 的这种非阻塞、单线程特性是代码执行如何可能影响队列中的所有请求以及它如何不影响其他语言的根本区别。因此,为了确保事件循环的健康性能,现代 Node.js 应用程序监控事件循环并收集可能影响 Node.js 应用程序性能的行为的重要指标至关重要。

内存泄漏

V8 内置的垃圾收集器 (GC) 会自动管理内存,开发人员不需要这样做。 V8 内存管理的工作方式与其他编程语言类似,同样,它也容易受到内存泄漏的影响。当应用程序代码在堆中保留内存并且在不再需要时未能释放该内存时会导致内存泄漏。随着时间的推移,未能释放保留的内存会导致内存使用量增加,从而导致机器上的内存使用量激增。如果选择忽略内存泄漏,Node.js 最终会抛出错误,因为进程内存不足,它会关闭。

为了了解 GC 的工作原理,您必须首先了解内存的活动区域和死区之间的区别。 V8 在内存中指向的任何对象都被视为活动对象。根对象——或指针链指向的任何对象——被认为是活的。其他一切都被认为是死的,并且是 GC 循环清理的目标。 V8 GC 引擎识别内存死区并尝试释放它们,以便它们再次可供操作系统使用。

在每个 V8 垃圾收集周期中,假设堆内存使用应该被完全清除。不幸的是,有些对象在 GC 循环后仍然存在于内存中,最终永远不会被清除。随着时间的推移,这些对象被认为是“泄漏”并将继续增长。最终,内存泄漏会增加您的内存使用量,并导致您的应用程序和服务器性能受到影响。在监控堆内存使用情况时,您应该注意前后的 GC 周期。具体来说,您应该注意完整的 GC 周期并跟踪堆使用情况。如果堆使用量随着时间的推移而增加,则这是可能存在内存泄漏的强烈迹象。作为一般规则,如果堆使用量增长超过几个 GC 周期并且最终没有清除,您应该担心。

一旦确定发生内存泄漏,您的选择是收集堆快照并了解随时间变化的差异。具体来说,您可能有兴趣了解哪些对象和类一直在稳步增长。执行堆转储可能会对您的应用程序造成负担,因此一旦发现内存泄漏,最好在预生产环境中诊断问题,这样您的生产应用程序就不会影响性能。诊断内存泄漏可能会很困难,但使用正确的工具,您可能能够检测到内存泄漏并最终诊断出问题。

应用拓扑

在此前 5 名列表中要衡量的最后一个性能组件是您的应用程序拓扑。由于云的出现,应用程序现在可以具有弹性:您的应用程序环境可以扩大和缩小以满足您的用户需求。因此,对您的应用程序拓扑进行清点以确定您的环境大小是否达到最佳非常重要。如果您有太多的虚拟服务器实例,那么您的云托管成本将会上升,但如果您没有足够的虚拟服务器实例,那么您的业务交易将会受到影响。

在此评估期间衡量两个指标很重要:

  • 业务交易负载
  • 容器性能

业务交易应该是基线的,你应该知道在任何给定时间满足你的基线所需的服务器数量。如果您的业务事务负载意外增加,例如超过正常负载标准差的两倍,那么您可能需要添加额外的服务器以满足这些用户。

另一个要衡量的指标是容器的性能。具体来说,您想要确定是否有任何服务器层受到胁迫,如果是,您可能希望向该层添加额外的服务器。跨层查看服务器很重要,因为单个服务器可能由于垃圾收集等因素而处于胁迫状态,但如果层中的大部分服务器处于胁迫状态,则可能表明该层无法支持负载它正在接收。

因为您的应用程序组件可以单独扩展,所以分析每个应用程序组件的性能并相应地调整您的拓扑非常重要。

结论

本文介绍了您在评估应用程序运行状况时可能想要衡量的前 5 个指标列表。总之,前 5 项是:

  • 商业交易
  • 外部依赖
  • 事件循环
  • 内存泄漏
  • 应用拓扑

在下一篇文章中,我们将把本系列的所有主题放在一起,介绍 AppDynamics 实施其 APM 战略所采用的方法。这不是一篇营销文章,而是解释为什么要做出某些决策和优化,以及它们如何为您提供有关虚拟或基于云的应用程序健康状况的强大视图。

有兴趣监控您的 Node.js 应用程序性能吗? 立即查看免费试用版!