共用方式為


Node.js 的最佳做法與疑難排解

在本文中,您將了解在 Azure App Service 上運行 iisnodeNode.js 應用程式的最佳實務與故障排除。

警告

在對實際執行網站進行疑難排解時請務必謹慎。 我們建議您在非實際執行的設定中 (例如預備位置) 對您的應用程式進行疑難排解。 問題修正後,請將您的預備位置與實際執行位置交換。

IISNODE 配置

結構描述檔案會顯示可針對 iisnode 設定的所有設定。 對您的應用有用的設定包括:

nodeProcessCountPerApplication

此設定會控制每個 IIS 應用程式啟動的節點處理序數目。 預設值為 1。 您可以將值變更為 0,以啟動與虛擬機器 vCPU 數量相同的 node.exe 處理序數目。 大多數應用程式的建議值是 0,這樣你就能同時使用你機器上的所有 vCPU。 Node.exe 是單一執行緒,因此一個 node.exe 最多耗用 1 個 vCPU。 為了讓你的 Node 應用程式發揮最大效能,建議全部使用 vCPU。

nodeProcessCommandLine

此設定會控制 node.exe 的路徑。 您可以設定此值以指向您的 node.exe 版本。

maxConcurrentRequestsPerProcess

此設定會控制 iisnode 傳送給每個 node.exe 的並行要求數目上限。 在 Azure App Service 中,預設值是無限。 您可以視您應用程式收到的要求數目以及您應用程式處理每個要求的速度而定,來設定此值。

maxNamedPipeConnectionRetry

為了將要求傳送至 node.exe,此設定會控制 iisnode 在具名管道上重試連線的次數上限。 此設定結合 namedPipeConnectionRetryDelay 一起使用,可決定 iisnode 內每個要求的總逾時。 Azure App Service 的預設值是 200Total Timeout in seconds = (maxNamedPipeConnectionRetry * namedPipeConnectionRetryDelay) / 1000

namedPipeConnectionRetryDelay

此設定會控制 iisnode 在每次重試之間應等待多少時間(以毫秒為單位),再將請求透過具名管線傳送給 node.exe。 預設值為 250 毫秒。 Total Timeout in seconds = (maxNamedPipeConnectionRetry * namedPipeConnectionRetryDelay) / 1000

預設情況下,iisnode 在 App Service 上的總逾時時間為 200 * 250 ms = 50 seconds

logDirectory

此設定會控制 iisnode 記錄 stdout/stderr 的目錄。 預設值為 iisnode,且相對於主要指令碼目錄 (主要 server.js 所在的位置)。

debuggerExtensionDll

這個設定控制 iisnode 在調試你的 Node.js 應用程式時所使用的 node-inspector 版本。 目前, 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 sockets 以使用這個版本。

flushResponse

預設情況下,IIS 會將回應資料緩衝到 4 MB 後再清除,或直到回應結束,以兩者中先發生者為準。 iisnode 提供可覆寫此行為的組態設定:若要在 iisnode 從 node.exe 接收到回應實體主體的片段時立即將其排清,您需要在 web.config 中將 iisnode/@flushResponse 屬性設定為 true

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

啟用回應實體主體每個片段的排清會增加效能額外負荷,並使系統的輸送量降低約 5% (截至 v0.1.13)。 最好只將此設定範圍限定於需要回應串流的端點(例如,使用 <location>web.config中的元素)。

此外,對於串流應用程式,你必須將 iisnode 處理器的 responseBufferLimit 設定為 0

<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 毫秒時,將其所有子處理序換出。 要了解 page out 的意思,請參見 EmptyWorkingSet 函式。 對於耗用大量記憶體和偶爾想要將記憶體移出至磁碟以釋放 RAM 的應用程式,此設定很有用。

警告

在生產應用程式上啟用下列組態設定時,請格外小心。 建議不要在實際生產應用程式上啟用這些設定。

debugHeaderEnabled

預設值為 false。 若設置為 true,iisnode 會在每個 HTTP 回應中添加一個 HTTP 回應標頭 iisnode-debug,且該標頭的值 iisnode-debug 是一個 URL。 查看 URL 片段即可取得個別的診斷資訊,但在瀏覽器中開啟 URL 可顯示視覺效果。

loggingEnabled

此設定會控制 iisnode 記錄 stdout 和 stderr 的功能。 iisnode 會從它啟動的節點程序擷取 stdout/stderr,並寫入 logDirectory 設定中指定的目錄。 一旦啟用,您的應用程式會將記錄寫入至檔案系統,而視應用程式所完成的記錄量而定,可能會影響效能。

devErrorsEnabled

預設值為 false。 當設置為true時,iisnode 會在瀏覽器上顯示 HTTP 狀態碼和 Win32 錯誤碼。 Win32 程式碼有助於偵錯某些類型的問題。

除錯啟用

不要在線上生產環境上啟用。

此設定控制除錯功能。 IISNODE 與 Node-Inspector 整合。 藉由啟用此設定,即可啟用節點應用程式的偵錯功能。 啟用此設定後,iisnode 會在第一次向節點應用程式發送除錯請求時,在 debuggerVirtualDir 目錄中建立節點檢查器檔案。 您可以將要求傳送至 http://yoursite/server.js/debug,以載入節點偵測器。 你可以用設定 debuggerPathSegment 來控制除錯網址區段。 預設情況下,debuggerPathSegment='debug'。 例如你可以設定 debuggerPathSegment 成 GUID,這樣比較難被發現。

案例和建議/疑難排解

我的節點應用程式進行太多的輸出呼叫

許多應用程式希望將外撥連線視為日常運作的一部分。 舉例來說,當有請求進來時,你的節點應用程式會想聯絡其他的 REST API,取得一些資訊來處理該請求。 在進行 HTTP 或 HTTPS 呼叫時,你會想使用 Keep Alive 代理程式。 您可以在進行這些輸出呼叫時,使用 agentkeepalive 模組作為您的保持連線代理程式。

agentkeepalive 模組確保 sockets 能在你的 Azure 網頁應用程式虛擬機中重複使用。 在每一個輸出要求上建立新通訊端會增加應用程式的負擔。 讓應用程式重複使用輸出要求的通訊端,可確保您的應用程式不會超過每個 VM 配置的 maxSockets。 Azure App Service 的建議是將 agentKeepAlive maxSockets 值設為總值為 (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
});

重要事項

這個例子假設你的虛擬機上有四個 node.exe 實例在執行。 如果你的數字不同,你必須相應調整 maxSockets 設定。

我的 Node 應用程式佔用太多 CPU。

你可能會在入口網站收到 Azure App Service 關於高 CPU 消耗的建議。 您也可以設定監視器以監看某些計量。 在 Azure Portal 儀表板查看 CPU 使用率時,請查看 CPU 的最大值,避免錯過峰值值。 如果你認為應用程式消耗太多 CPU,且無法解釋原因,你可以透過 node 應用程式的設定檔來找出原因。

我的 Node 應用程式佔用太多記憶體

如果你的應用程式佔用過多記憶體,你會在入口網站上看到 Azure App Service 發出的高記憶體使用通知。 您可以設定監視器以監看某些計量。 在 Azure 入口網站儀表板查看記憶體使用量時,務必檢查記憶體的 MAX 值,避免錯過峰值值。

Node.js 的流失偵測和堆積區分

您可以使用 node-memwatch 協助找出記憶體流失。 如同 v8 分析工具,您可以安裝 memwatch 並編輯您的程式碼來擷取和區分堆積,以找出您應用程式中的記憶體流失。

我的 node.exe 個體隨機被殺

node.exe 會隨機關閉有幾個原因:

  • 您的應用程式正在擲出未處理的例外狀況。 請檢查 d:\home\LogFiles\Application\logging-errors.txt 檔案以了解拋出的例外細節。 這個檔案有堆疊追蹤,可協助您對應用程式進行偵錯並加以修正。
  • 你的應用程式會消耗過多記憶體,這會影響其他程序的啟動。 如果總 VM 記憶體接近 100%,你的 node.exe 實例可能會被程序管理器終止。 程序管理員會終止某些處理程序,讓其他處理程序有機會執行一些工作。 若要修正此問題,可分析您應用程式的記憶體流失。 如果您的應用程式需要大量記憶體,請擴大至較大的 VM (這樣會增加 VM 的可用 RAM)。

我的 Node 應用程式無法啟動

如果你的應用程式開始時回傳 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 應用程式啟動時間太慢(冷啟動)

應用程式啟動時間過長通常是因為 node_modules 中有大量檔案。 應用程式會嘗試在啟動時載入大部分檔案。 根據預設,因為您的檔案會儲存在 Azure App Service 的網路共用上,所以載入多個檔案可能需要一些時間。 讓處理程序速度變快的解決方式如下︰

  • 試著延遲載入您的 node_modules,而且不要在應用程式啟動時載入所有模組。 若要延遲載入模組,應在實際需要該模組時,於函式內、在模組程式碼首次執行之前呼叫 require ('module')。
  • Azure App Service 會提供稱為本機快取的功能。 這項功能會將您的內容從網路共用複製到 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 重寫規則,或檢查您的快速應用程式是否已定義正確的路由。
- 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 App Service 中,這個值設為 5000,表示 node.exe 在指定的管道上一次可以接受 5,000 個請求。 這個值應足以滿足大部分在 Azure App Service 上執行的節點應用程式。 你不應該在 Azure App Service 上看到 503.1003,因為 NODE_PENDING_PIPE_INSTANCES 的值過高。