你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

Node.js 的最佳做法和故障排除

本文介绍有关使用 iisnode 在 Azure 应用服务上运行 Node.js 应用程序的最佳做法和故障排除。

警告

排查生产站点上的问题时,请务必小心谨慎。 我们建议您在非生产环境(如预备环境)上对应用进行故障排查。 修复问题后,请将过渡槽与生产槽交换。

iisnode 配置

架构文件显示可针对 iisnode 配置的所有设置。 对应用程序有用的一些设置包括:

nodeProcessCountPerApplication

此设置控制每个 IIS 应用程序启动的节点进程数目。 默认值为 1。 可以通过将值更改为 0 来启动与虚拟机 vCPU 计数一样多的 node.exe 进程。 对于大多数应用程序,建议的值为 0,以便在计算机上使用所有 vCPU。 Node.exe 占用单线程,因此,一个 node.exe 最多消耗用 1 个 vCPU。 若要充分利用节点应用程序的性能,请使用所有 vCPU。

nodeProcessCommandLine

此设置控制 node.exe 的路径。 可以设置此值以指向 node.exe 版本。

maxConcurrentRequestsPerProcess

此设置控制 iisnode 发送给每个 node.exe 的并发请求数目上限。 在 Azure 应用服务上,默认值为 Infinite。 可以根据应用程序收到的请求数目以及应用程序处理每个请求的速度来配置此值。

maxNamedPipeConnectionRetry

此设置控制 iisnode 在命名管道上重试连接,以将请求发送到 node.exe 的次数上限。 此设置与 namedPipeConnectionRetryDelay 结合使用,可确定 iisnode 内每个请求的总超时。 Azure 应用服务中的默认值为 200Total Timeout in seconds = (maxNamedPipeConnectionRetry * namedPipeConnectionRetryDelay) / 1000

namedPipeConnectionRetryDelay

此设置控制 iisnode 在每次重试之间等待的时间量,以便通过命名管道将请求发送到 node.exe。 默认值为 250 毫秒。 Total Timeout in seconds = (maxNamedPipeConnectionRetry * namedPipeConnectionRetryDelay) / 1000

默认情况下,在应用服务上的 iisnode 中,总超时时间为 200 * 250 ms = 50 seconds

logDirectory

此设置控制 iisnode 用于记录 stdout/stderr 的目录。 默认值为 iisnode,它相对于主脚本目录(其中存在主 server.js )。

debuggerExtensionDll

此设置控制调试节点应用程序时 iisnode 使用的节点检查器版本。 目前, iisnode-inspector-0.7.3.dlliisnode-inspector.dll 是此设置的唯一两个有效值。 默认值 为iisnode-inspector-0.7.3.dll。 iisnode-inspector-0.7.3.dll 版本使用 node-inspector-0.7.3 并使用 Web 套接字。 在 Azure Web 应用上启用 Web 套接字以使用此版本。

flushResponse

默认情况下,IIS 会在刷新前缓冲高达 4 MB 的响应数据,或直到响应结束(以先到第一者为准)。 iisnode 提供一个配置设置,可以覆盖此行为:您需要在 iisnode/@flushResponse 中,将属性设置为 true,以便在 iisnode 从 node.exe 接收到响应实体正文的片段时立即对其进行刷新。

<configuration>
    <system.webServer>
        <!-- ... -->
        <iisnode flushResponse="true" />
    </system.webServer>
</configuration>

启用刷新响应实体的每个片段会增加性能负担,从而使系统吞吐量减少约 5%(截至 v0.1.13)。 最好仅将此设置的范围限定为需要响应流的终结点(例如,在 `<location>` 元素 web.config 中使用)。

此外,对于流媒体应用程序,必须将 iisnode 处理程序设置为 responseBufferLimit0

<handlers>
    <add name="iisnode" path="app.js" verb="\*" modules="iisnode" responseBufferLimit="0"/>
</handlers>

watchedFiles

一个以分号分隔的文件列表,系统将监视其更改。 任何文件更改会导致应用程序回收。 每个条目由可选的目录名称和必需的文件名组成,这些名称和文件名是相对于主应用程序入口点所在的目录。 只有文件名部分可以使用通配符。 默认值为 *.js;iisnode.yml

recycleSignalEnabled

默认值是 false。 如果启用,节点应用程序可以连接到命名管道(环境变量 IISNODE_CONTROL_PIPE),并发送 回收 消息。 可以通过此方式正常回收 w3wp。

idlePageOutTimePeriod

默认值为 0,这意味着此功能已禁用。 当设置为大于 0 的某个值时,iisnode 会每隔 idlePageOutTimePeriod 毫秒将其所有子进程移出内存。 若要了解 页面调出 的含义,请参阅 EmptyWorkingSet 函数。 对于消耗大量内存并且偶尔想要将内存页出至磁盘以释放 RAM 的应用程序,此设置很有用。

警告

在生产应用程序上启用以下配置设置时,请格外小心。 建议不要在实际生产应用程序上启用它们。

debugHeaderEnabled

默认值是 false。 如果设置为 true,iisnode 会将 HTTP 响应标头 iisnode-debug 添加到它发送的每个 HTTP 响应中,iisnode-debug 标头值为一个 URL。 查看 URL 片段即可收集各项诊断信息,但在浏览器中打开该 URL 可达到更好的视觉效果。

loggingEnabled

此设置控制 iisnode 记录 stdout 和 stderr 的功能。 iisnode 从节点进程捕获 stdout/stderr,并写入 logDirectory 设置中指定的目录。 一旦启用,应用程序会将日志写入文件系统,这可能会影响性能,但具体要视应用程序完成的日志记录量而定。

devErrorsEnabled

默认值是 false。 如果设置为 true,iisnode 会在浏览器中显示 HTTP 状态代码和 Win32 错误代码。 Win32 代码有助于调试某些类型的问题。

debuggingEnabled

切勿在线上生产环境启用。

此设置控制调试功能。 iisnode 与 node-inspector 集成。 通过启用此设置,可启用节点应用程序的调试功能。 启用此设置后,iisnode 会在 调试器VirtualDir 目录中创建对节点应用程序的第一个调试请求中的节点检查器文件。 可将请求发送到 http://yoursite/server.js/debug,以加载 node-inspector。 可以使用 debuggerPathSegment 配置项来控制调试 URL 段。 默认情况下,debuggerPathSegment='debug'。 例如,可以将 debuggerPathSegment 设置为 GUID,以便其他人更难发现。

方案和建议/故障排除

Node 应用程序发出的出站调用过多

许多应用程序希望在其常规操作期间进行出站连接。 例如,当请求传入时,节点应用希望在其他位置联系 REST API,并获取一些信息来处理请求。 在进行 HTTP 或 HTTPS 调用时,建议使用保持活跃代理。 可在进行这些出站调用时,使用 agentkeepalive 模块作为保持连接代理。

Agentkeepalive 模块可确保套接字在 Azure Web 应用程序的虚拟机上重复使用。 在每个出站请求中创建新套接字会增大应用程序的开销。 让应用程序对出站请求重复使用套接字可确保应用程序不会超过为每个 VM 分配的 maxSockets。 有关 Azure 应用服务的建议是将 agentKeepAlive maxSocket 值设置为总计 (four instances of node.exe * 32 maxSockets/instance) 128 sockets per VM

agentKeepALive 配置示例:

let keepaliveAgent = new Agent({
    maxSockets: 32,
    maxFreeSockets: 10,
    timeout: 60000,
    freeSocketTimeout: 300000
});

重要说明

此示例假定 VM 上运行有四个 node.exe 实例。 如果你有其他数字,则必须相应地修改 maxSocket 设置。

节点应用程序消耗过多的 CPU

你可能会在 Azure 门户中收到 Azure 应用服务有关高 CPU 消耗的建议。 也可将监视器设置为监视某些指标。 在 Azure 门户仪表板上检查 CPU 使用率时,请检查 CPU 的 MAX 值,以免错过峰值。 如果认为应用程序消耗过多的 CPU,并且无法解释原因,则可以分析节点应用程序以找出问题。

节点应用程序消耗过多的内存

如果应用程序占用过多的内存,则门户中的 Azure 应用服务会显示有关内存消耗量过高的通知。 可将监视器设置为监视某些指标。 在 Azure 门户仪表板上检查内存使用情况时,请务必检查内存的 MAX 值,以免错过峰值。

Node.js 的泄漏检测和堆区分

可以使用 node-memwatch 帮助识别内存泄漏。 可以像安装 v8-profiler 一样安装 memwatch,并编辑代码来捕获和区分堆,以找出应用程序中的内存泄漏。

我的 node.exe 实例被随机终止

node.exe 随机关闭的原因有几个:

  • 应用程序抛出了未捕获的异常。 检查 d:\home\LogFiles\Application\logging-errors.txt 文件,了解引发的异常的详细信息。 此文件提供堆栈跟踪以帮助调试和修复应用程序。
  • 您的应用程序消耗了过多内存,影响了其他进程的启动。 如果 VM 内存总量接近 100%,则进程管理器可能会终止 node.exe 实例。 进程管理器终止某些进程后,其他进程便有机会执行一些工作。 若要解决此问题,请探查应用程序中的内存泄漏问题。 如果应用程序需要大量的内存,请纵向扩展为更大的 VM(增加 VM 的可用 RAM)。

我的节点应用程序未启动

如果应用程序启动时返回 500 个错误,则可能有几个原因:

  • Node.exe 不存在于正确的位置。 检查nodeProcessCommandLine设置。
  • 主脚本文件不存在于正确的位置。 检查 web.config 并确保处理程序部分中主脚本文件的名称与主脚本文件匹配。
  • Web.config 配置不正确。 检查设置名称和值。
  • 冷启动:应用程序启动时间过长。 如果应用程序花费的时间超过 (maxNamedPipeConnectionRetry * namedPipeConnectionRetryDelay) / 1,000 seconds,iisnode 将返回 500 错误。 增加这些设置的值,以便与应用程序启动时间匹配,从而防止 iisnode 超时并返回 500 错误。

节点应用程序崩溃

应用程序正在引发未捕获的异常。 检查 d:\home\LogFiles\Application\logging-errors.txt 有关引发的异常的详细信息。 此文件提供堆栈跟踪以帮助诊断和修复应用程序。

节点应用程序启动时间过长(冷启动)

应用程序启动时间过长的最常见原因是 node_modules 中有大量文件。 应用程序在启动时会尝试加载其中的大多数文件。 默认情况下,由于文件存储在 Azure 应用服务的网络共享上,因此加载过多的文件可能需要一段时间。 加速此过程的某些解决方法包括:

  • 尝试延迟加载 node_modules,而不要在应用程序启动时加载所有模块。 若要延迟加载模块,在首次执行模块代码之前,在函数内实际需要模块时,应调用 require('module')。
  • Azure 应用服务提供一项称为本地缓存的功能。 此功能会将内容从网络共享复制到 VM 上的本地磁盘。 由于文件位于本地,因此,node_modules 的加载时间快很多。

iisnode HTTP 状态和子状态

cnodeconstants 源文件列出了 iisnode 由于错误而返回的所有可能状态或子状态组合。

为应用程序启用 FREB 以查看 Win32 错误代码。 请确保仅在非生产站点上启用 FREB,因为性能原因。

HTTP 状态 HTTP 子状态 可能的原因
500 1000 向 iisnode 调度请求时出现问题。 检查是否已启动 node.exe。 Node.exe 在启动时可能崩溃。 检查 web.config 配置是否存在错误。
500 1001 - Win32Error 0x2:应用未响应 URL。 检查 URL 重写规则,或检查是否为 Express 应用定义了正确的路由。
- Win32Error 0x6d:命名管道正忙。 Node.exe 无法接受请求,因为管道忙碌。 检查 CPU 使用率是否偏高。
- 其他错误:检查 node.exe 是否崩溃。
500 1002 Node.exe 崩溃。 检查 d:\home\LogFiles\logging-errors.txt 以获取堆栈跟踪。
500 1003 管道配置问题。 命名管道配置不正确。
500 1004-1018 发送请求或处理 node.exe 的相关响应时发生某个错误。 检查 node.exe 是否已崩溃。 请查看 d:\home\LogFiles\logging-errors.txt 以获取堆栈跟踪。
503 1000 内存不足,无法分配更多命名管道连接。 检查应用为何耗用这么多内存。 检查 maxConcurrentRequestsPerProcess 设置值。 如果此值并非无限,而且有许多请求,请增大此值来防止此错误。
503 1001 无法将请求调度到 node.exe,因为应用程序正在回收。 回收应用程序后,应正常处理请求。
503 1002 检查 Win32 错误代码,了解实际原因。 无法将请求调度到 node.exe。
503 1003 命名管道太忙。 验证 node.exe 是否消耗过多的 CPU。

Node.exe 有一个名为 NODE_PENDING_PIPE_INSTANCES 的设置。 在 Azure 应用服务上,此值设置为 5000,这意味着 node.exe 可以在命名管道上一次接受 5,000 个请求。 此值应足以满足 Azure 应用服务中运行的大多数 node 应用程序。 由于 NODE_PENDING_PIPE_INSTANCES 值过高,你不应该在 Azure 应用服务中看到 503.1003。