Nuxt3+PM2叢集模式啟動及勘誤

夜尽丶發表於2024-10-14

起因

之前寫過一篇 Nuxt3 的文章,Nuxt3 環境變數配置,用到了 PM2,但是裡面的一些配置存在問題,最近有空又驗證了一下,這裡做一個勘誤。

問題

PM2 的啟動配置中有一項是exec_mode,預設是fork,另一個可選值是clusterfork 是單程序模式,cluster 是多程序模式,也就是常說的叢集模式。

最早開始用 Nuxt3 的時候,還在內測階段,當時找到的資料很多都是基於 Nuxt2 的,Nuxt3 的文件也不是很全,所以很多配置都是參考 Nuxt2 的,有點病急亂投醫了,最後拼湊出一套能正常啟動的配置就沒有再調整了,詳情可以看之前的文章,這裡把有問題的欄位挑出來。

{
  exec_mode: "cluster",
  instances: "max", // Or a number of instances
  script: "npm",
  args: "start",
}

這裡的配置造成了什麼問題呢?首先可以看出來是透過 npm 來啟動程式的,透過npm run start這個命令來執行package.json中的start指令碼node .output/server/index.mjs,首先這樣是可以啟動的,但是存在一些問題:

伺服器偶爾會出現 CPU 佔用過高的情況,檢視 CPU 佔用情況發現是 node 程序,於是定位到 PM2,檢視執行情況發現多個程序只有一個啟動成功,其他的程序都在反覆重啟,CPU 自然升高。再去檢視日誌發現是因為埠被佔用導致只有一個程序能啟動成功,這時我意識到配置可能有問題,不過當時沒有時間調整,於是一直以來都是透過手動停止其他程序來解決問題。

解決

有問題當然要解決,叢集模式我接觸的不多,但既然有這個配置,肯定不會因為埠占用就無法啟動,Nuxt3 至今已有較大的版本變化,於是我再次翻看 Nuxt3 的文件,看下官方是怎麼配置 PM2 的:

docs/getting-started/deployment

module.exports = {
  apps: [
    {
      name: "NuxtAppName",
      port: "3000",
      exec_mode: "cluster",
      instances: "max",
      script: "./.output/server/index.mjs",
    },
  ],
};

最早我是沒覺得問題出在啟動指令碼這的,直到我又找到一個 github 上的 issue Port Already in Use in Cluster Mode,包括裡面關聯的問題都提到了不應使用 npm 來啟動,而是直接使用指令碼路徑。

You can't cluster application via npm start. To make cluster work, in the script attribute of your ecosystem.config.js, directly put the path of your javascript app.

透過 npm 啟動時並沒有將這個程序直接託管給 pm2,而是透過 npm 啟動了一個程序,pm2 只是監控這個程序,所以 pm2 並不能很好地管理這個程序,上面的截圖中也可以看到版本號是 0.39.7,其實這個是伺服器上 nvm 的版本,而不是 nuxt3 程式的版本。

關於叢集模式

最早我懷疑是叢集模式的問題,但即使改成 fork,也還是會出現埠占用的報錯,雖然可以透過修改instances來解決,但隱約覺得不是正確的方法,在解決啟動報錯問題之後,我再次嘗試了使用叢集模式,不過我仍然不太清楚是否應該使用這個配置,於是我做了一些測試,只是在本地環境的一些測試,結果並不準確,只能做個參考。

instances是要使用的程序數量,它的值可以是'max'-1或其他數字,'max'表示使用最大的例項數,-1表示使用最少的基本就是 1 個,其他數字表示使用指定數量的例項數,這個例項數是根據 CPU 核心數來計算的,比如單核雙執行緒的 CPU,例項數就是 2。

首先我在本地啟動了一個 nuxt3 專案,這裡模擬伺服器環境只用了 2 個例項,然後使用兩種不同的 pm2 啟動方式執行。

使用pm2 monit監控程序,可以看到這時還沒什麼區別,這時用 jmeter 進行壓測,建立 500 個執行緒訪問叢集模式的程序,可以看到兩個程序都在執行:

然後同樣的壓測,但是使用 fork 模式,可以看到只有一個程序在執行:

我並不瞭解壓測,只是簡單對比一下,可以看出叢集模式的 CPU 波動還是比較明顯的,fork 模式 CPU 的波動不明顯,但是記憶體佔用會極速攀升,沒有截到圖。繼續增加壓測執行緒,記憶體的變化並不明顯,叢集模式的 CPU 佔用會更加明顯,也有可能是因為壓測應用和被壓測應用都在本地,所以這個測試結果並不準確,在錯誤率方面,也沒有測出兩者的區別。透過簡單的測試並沒有感受出優劣,叢集的優勢可能體現在效能和容錯方面,在硬體上看不出太多效果,這裡只是做一個記錄,具體還需要更多的實踐經驗。

叢集模式允許聯網的 Node.js 應用程式(http(s)/tcp/udp 伺服器)在所有可用的 cpu 上擴充套件,無需任何程式碼修改。根據可用 cpu 的數量,這將極大地提高應用程式的效能和可靠性。

相關文章