溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Node多進(jìn)程模型和項(xiàng)目如何部署

發(fā)布時(shí)間:2022-12-27 10:43:44 來源:億速云 閱讀:110 作者:iii 欄目:web開發(fā)

這篇文章主要介紹“Node多進(jìn)程模型和項(xiàng)目如何部署”的相關(guān)知識(shí),小編通過實(shí)際案例向大家展示操作過程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“Node多進(jìn)程模型和項(xiàng)目如何部署”文章能幫助大家解決問題。

進(jìn)程 VS 線程

進(jìn)程

進(jìn)程(process)是計(jì)算機(jī)操作系統(tǒng)分配和調(diào)度任務(wù)的基本單位。打開任務(wù)管理器,可以看到其實(shí)在計(jì)算機(jī)的后臺(tái)運(yùn)行著非常多的程序,每個(gè)程序都是一個(gè)進(jìn)程。

Node多進(jìn)程模型和項(xiàng)目如何部署

現(xiàn)代瀏覽器基本都是多進(jìn)程架構(gòu)的,以 Chrome 瀏覽器為例,打開“更多工具” - “任務(wù)管理器”,就能看到當(dāng)前瀏覽器的進(jìn)程信息,其中一個(gè)頁(yè)面就是一個(gè)進(jìn)程,除此之外,還有網(wǎng)路進(jìn)程,GPU 進(jìn)程等。

Node多進(jìn)程模型和項(xiàng)目如何部署

多進(jìn)程的架構(gòu),得以保證應(yīng)用更穩(wěn)定的運(yùn)行。還是以瀏覽器為例,假如所有的程序都運(yùn)行在一個(gè)進(jìn)程中,如果網(wǎng)絡(luò)出現(xiàn)故障,或者頁(yè)面渲染出錯(cuò)問題,都會(huì)導(dǎo)致整個(gè)瀏覽器的崩潰。通過多進(jìn)程的架構(gòu),哪怕網(wǎng)絡(luò)進(jìn)程崩潰了,它不會(huì)影響到已有頁(yè)面的展示,最壞也就是暫時(shí)不能接入網(wǎng)絡(luò)。

線程

線程(thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。舉一個(gè)例子,一個(gè)程序好比是一家公司,下設(shè)多個(gè)部門,就是若干個(gè)進(jìn)程;每個(gè)部門的通力合作使得公司正常運(yùn)行,而線程就是員工,是具體干活的人。

我們都知道 JavaScript 是一門單線程語言。這么設(shè)計(jì)是因?yàn)樵缙?JS 主要用來編寫腳本程序,負(fù)責(zé)實(shí)現(xiàn)頁(yè)面的交互效果。如果設(shè)計(jì)成多線程語言,一是沒有必要,二是多個(gè)線程共同操作一個(gè) dom 節(jié)點(diǎn),那么瀏覽器該聽誰的?當(dāng)然隨著技術(shù)的發(fā)展,現(xiàn)在的 JS 也支持了多線程,不過僅用來處理一些和 dom 操作無關(guān)的邏輯。

單進(jìn)程存在的問題

單線程單進(jìn)程帶來一個(gè)嚴(yán)重的問題,一個(gè)運(yùn)行中的 node.js 程序,一旦主線程掛掉,那么這個(gè)進(jìn)程也就掛掉了,整個(gè)應(yīng)用也就隨之掛掉。再者,現(xiàn)代計(jì)算機(jī)大都是多核 CPU,四核八線程,八核十六線程,都是很常見的設(shè)備了。而 node.js 作為一個(gè)單進(jìn)程的程序,白白浪費(fèi)掉了多核 CPU 的性能。

針對(duì)這種情況,我們需要一個(gè)合適的多進(jìn)程模型,將一個(gè)單進(jìn)程的 node.js 程序變?yōu)槎噙M(jìn)程的架構(gòu)。

Node.js 的多進(jìn)程實(shí)現(xiàn)

Node.js 實(shí)現(xiàn)多進(jìn)程架構(gòu)有兩種常用方案,都是使用原生模塊,分別是 child_process 模塊和 cluster 模塊。

child_process

child_process 是 node.js 的內(nèi)置模塊,看名字也能猜到它負(fù)責(zé)的是和子進(jìn)程有關(guān)的事。

我們不再細(xì)說該模塊的具體用法,實(shí)際上它大概只有六七個(gè)方法,還是非常容易理解的。我們使用其中的一個(gè) fork 方法來演示如何實(shí)現(xiàn)多進(jìn)程以及多進(jìn)程之間的通信。

先看下準(zhǔn)備好的演示案例的目錄結(jié)構(gòu):

Node多進(jìn)程模型和項(xiàng)目如何部署

我們使用 http 模塊創(chuàng)建了一個(gè) http server,當(dāng)有 /sum 請(qǐng)求進(jìn)來時(shí),會(huì)通過 child_process 模塊創(chuàng)建一個(gè)子進(jìn)程,并通知子進(jìn)程執(zhí)行計(jì)算的邏輯,同時(shí)父進(jìn)程也要監(jiān)聽子進(jìn)程發(fā)來的消息:

// child_process.jsconst http = require('http')const { fork } = require('child_process')const server = http.createServer((req, res) => {
  if (req.url == '/sum') {
    // fork 方法接收一個(gè)模塊路徑,然后開啟一個(gè)子進(jìn)程,將模塊在子進(jìn)程中運(yùn)行
    // childProcess 表示創(chuàng)建的子進(jìn)程
    let childProcess = fork('./sum.js')

    // 發(fā)消息給子進(jìn)程
    childProcess.send('子進(jìn)程開始計(jì)算')

    // 父進(jìn)程中監(jiān)聽子進(jìn)程的消息
    childProcess.on('message', (data) => {
      res.end(data + '')
    })

    // 監(jiān)聽子進(jìn)程的關(guān)閉事件
    childProcess.on('close', () => {
      // 子進(jìn)程正常退出和報(bào)錯(cuò)掛掉,都會(huì)走到這里
      console.log('子進(jìn)程關(guān)閉')
      childProcess.kill()
    })

    // 監(jiān)聽子進(jìn)程的錯(cuò)誤事件
    childProcess.on('error', () => {
      console.log('子進(jìn)程報(bào)錯(cuò)')
      childProcess.kill()
    })
  }
    
  if (req.url == '/hello') {
    res.end('hello')
  }
  
  // 模擬父進(jìn)程報(bào)錯(cuò)
  if (req.url == '/error') {
     throw new Error('父進(jìn)程出錯(cuò)')
     res.end('hello')
   }
})

server.listen(3000, () => {
  console.log('Server is running on 3000')
})復(fù)制代碼

sum.js 用來模擬子進(jìn)程要執(zhí)行的任務(wù)。子進(jìn)程監(jiān)聽父進(jìn)程發(fā)來的消息,處理計(jì)算任務(wù),然后將結(jié)果發(fā)送給父進(jìn)程:

// sum.jsfunction getSum() {
  let sum = 0
  for (let i = 0; i < 10000 * 1000 * 100; i++) {
    sum += 1
  }

  return sum
}// process 是 node.js 中一個(gè)全局對(duì)象,表示當(dāng)前進(jìn)程。在這里也就是子進(jìn)程。// 監(jiān)聽主進(jìn)程發(fā)來的消息process.on('message', (data) => {
  console.log('主進(jìn)程的消息:', data)
    
  const result = getSum()
  // 將計(jì)算結(jié)果發(fā)送給父進(jìn)程
  process.send(result)
})復(fù)制代碼

打開終端,運(yùn)行命令 node 1.child_process

Node多進(jìn)程模型和項(xiàng)目如何部署

訪問瀏覽器:

Node多進(jìn)程模型和項(xiàng)目如何部署

接著來模擬子進(jìn)程報(bào)錯(cuò)的情況:

// sum.jsfunction getSum() {
  // ....}// 子進(jìn)程運(yùn)行5s后,模擬進(jìn)程掛掉
 setTimeout(() => {
   throw new Error('報(bào)錯(cuò)')
 }, 1000 * 5)

process.on('message', (data) => {
  // ...})復(fù)制代碼

再次訪問瀏覽器,5秒之后觀察控制臺(tái):

Node多進(jìn)程模型和項(xiàng)目如何部署

子進(jìn)程已經(jīng)掛掉了,然后再訪問另一個(gè) url :/hello

Node多進(jìn)程模型和項(xiàng)目如何部署

可見,父進(jìn)程依然能正確處理請(qǐng)求,說明子進(jìn)程報(bào)錯(cuò),并不會(huì)影響父進(jìn)程的運(yùn)行。

接著我們來模擬父進(jìn)程報(bào)錯(cuò)的場(chǎng)景,注釋掉 sum.js 模塊的模擬報(bào)錯(cuò),然后重啟服務(wù),瀏覽器訪問 /error

Node多進(jìn)程模型和項(xiàng)目如何部署

發(fā)現(xiàn)父進(jìn)程掛掉后,整個(gè) node.js 程序自動(dòng)退出了,服務(wù)完全崩潰,沒有挽回的余地。

可見,通過 child_processfork 方法實(shí)現(xiàn) node.js 的多進(jìn)程架構(gòu)并不復(fù)雜。進(jìn)程間的通信主要通過 sendon 方法,從這個(gè)命名上也能知道,其底層應(yīng)該是一個(gè)發(fā)布訂閱模式。

但是它存在一個(gè)嚴(yán)重的問題,雖然子進(jìn)程不影響父進(jìn)程,但是一旦父進(jìn)程出錯(cuò)掛掉,所有的子進(jìn)程會(huì)被”一鍋端掉“ 。所以,這種方案適用于將一些復(fù)雜耗時(shí)的運(yùn)算,fork 出一個(gè)單獨(dú)的子進(jìn)程去做。更準(zhǔn)確的來說,這種用法是用來代替多線程的實(shí)現(xiàn),而非多進(jìn)程。

cluster

使用 child_process 模塊實(shí)現(xiàn)多進(jìn)程,貌似不堪大用。所以一般更推薦使用 cluster 模塊來實(shí)現(xiàn) node.js 的多進(jìn)程模型。

cluster,集群的意思,這個(gè)名詞相信大家都不陌生。打個(gè)比方,以前公司只有一個(gè)前臺(tái),有時(shí)候太忙就沒辦法及時(shí)接待訪客?,F(xiàn)在公司分配了4個(gè)前臺(tái),即使有三個(gè)都在忙,也還有一個(gè)能接待新來的訪客。集群大致也就是這個(gè)意思,對(duì)于同一件事,合理的分配給不同的人去干,以此來保證這件事能做到最好。

cluster 模塊的使用也比較簡(jiǎn)單。如果當(dāng)前進(jìn)程是主進(jìn)程,則根據(jù) CPU 的核數(shù)創(chuàng)建合適數(shù)量的子進(jìn)程,同時(shí)監(jiān)聽子進(jìn)程的 exit 事件,有子進(jìn)程退出,就重新 fork 新的子進(jìn)程。如果不是子進(jìn)程,則進(jìn)行實(shí)際業(yè)務(wù)的處理。

const http = require('http')const cluster = require('cluster')const cpus = require('os').cpus()if (cluster.isMaster) {
  // 程序啟動(dòng)時(shí)首先走到這里,根據(jù) CPU 的核數(shù),創(chuàng)建出多個(gè)子進(jìn)程
  for (let i = 0; i < cpus.length; i++) {
    // 創(chuàng)建出一個(gè)子進(jìn)程
    cluster.fork()
  }

  // 當(dāng)任何一個(gè)子進(jìn)程掛掉后,cluster 模塊會(huì)發(fā)出'exit'事件。此時(shí)通過再次調(diào)用 fork 來來重啟進(jìn)程。
  cluster.on('exit', () => {
    cluster.fork()
  })
} else {
  // fork 方法執(zhí)行創(chuàng)建子進(jìn)程,同時(shí)會(huì)再次執(zhí)行該模塊,此時(shí)邏輯就會(huì)走到這里
  const server = http.createServer((req, res) => {
    console.log(process.pid)
    res.end('ok')
  })

  server.listen(3000, () => {
    console.log('Server is running on 3000', 'pid: ' + process.pid)
  })
}復(fù)制代碼

啟動(dòng)服務(wù):

Node多進(jìn)程模型和項(xiàng)目如何部署

可以看到,cluster 模塊創(chuàng)建出了非常多的子進(jìn)程,好像是每個(gè)子進(jìn)程都運(yùn)行著同一個(gè)web服務(wù)。

需要注意的是,此時(shí)并非是這些子進(jìn)程共同監(jiān)聽同一個(gè)端口。端口的監(jiān)聽依然是由 createServer 方法創(chuàng)建的 server 去負(fù)責(zé),將請(qǐng)求轉(zhuǎn)發(fā)給各個(gè)子進(jìn)程。

我們編寫一個(gè)請(qǐng)求腳本,來請(qǐng)求上面的服務(wù),看下效果。

// request.jsconst http = require('http')for (let i = 0; i < 1000; i++) {
  http.get('http://localhost:3000')
}復(fù)制代碼

http 模塊不僅可以創(chuàng)建 http server,還能用來發(fā)送 http 請(qǐng)求。Axios支持瀏覽器和服務(wù)器環(huán)境,在服務(wù)器端就是使用 http 模塊發(fā)送 http 請(qǐng)求。

使用 node 命令執(zhí)行該文件,再看下原來的控制臺(tái):

Node多進(jìn)程模型和項(xiàng)目如何部署

打印出了具體處理請(qǐng)求的不同子進(jìn)程的進(jìn)程ID。

這就是通過 cluster 模塊實(shí)現(xiàn)的 nodd.js 的多進(jìn)程架構(gòu)。

當(dāng)然,我們?cè)诓渴?node.js 項(xiàng)目時(shí)不會(huì)這么干巴巴的寫和使用 cluster 模塊。有一個(gè)非常好用的工具,叫做 PM2,它是一個(gè)基于 cluster 模塊實(shí)現(xiàn)的進(jìn)程管理工具。在后面的章節(jié)中會(huì)介紹它的基本用法。

小結(jié)

到此為止,我們花了一部分篇幅介紹 node.js 中多進(jìn)程的知識(shí),其實(shí)僅是想要交代下為什么需要使用 pm2 來管理 node.js 應(yīng)用。本文由于篇幅有限,再加上描述不夠準(zhǔn)確/詳盡,僅做簡(jiǎn)單介紹。如果是第一次接觸這一塊內(nèi)容的朋友,可能沒有太明白,也不打緊,后面會(huì)再出一篇更細(xì)節(jié)的文章。

部署實(shí)踐

準(zhǔn)備一個(gè) express 項(xiàng)目

本文已經(jīng)準(zhǔn)備了一個(gè)使用 express 開發(fā)的示例程序,點(diǎn)此訪問。

它主要實(shí)現(xiàn)了一個(gè)接口服務(wù),當(dāng)訪問 /api/users 時(shí),使用 mockjs 模擬了10條用戶數(shù)據(jù),返回一個(gè)用戶列表。同時(shí)會(huì)開啟一個(gè)定時(shí)器,來模擬報(bào)錯(cuò)的情況:

const express = require('express')const Mock = require('mockjs')const app = express()

app.get("/api/users", (req, res) => {
  const userList = Mock.mock({
    'userList|10': [{
      'id|+1': 1,
      'name': '@cname',
      'email': '@email'
    }]
  })
  
  setTimeout(()=> {
      throw new Error('服務(wù)器故障')
  }, 5000)

  res.status(200)
  res.json(userList)
})

app.listen(3000, () => {
  console.log("服務(wù)啟動(dòng): 3000")
})復(fù)制代碼

本地測(cè)試一下,在終端中執(zhí)行命令:

node server.js復(fù)制代碼

打開瀏覽器,訪問用戶列表接口:

Node多進(jìn)程模型和項(xiàng)目如何部署

五秒鐘后,服務(wù)器會(huì)掛掉:

Node多進(jìn)程模型和項(xiàng)目如何部署

后面我們使用 pm2 來管理應(yīng)用后,就可以解決這個(gè)問題。

討論:express 項(xiàng)目是否需要打包

通常完成一個(gè) vue/react 項(xiàng)目后,我們都會(huì)先執(zhí)行打包,再進(jìn)行發(fā)布。其實(shí)前端項(xiàng)目要進(jìn)行打包,主要是因?yàn)槌绦蜃罱K的運(yùn)行環(huán)境是瀏覽器,而瀏覽器存在各種兼容性問題和性能問題,比如:

  • 高級(jí)語法的不支持,需要將 ES6+ 編譯為 ES5 語法

  • 不能識(shí)別 .vue.jsx,.ts 文件,需要編譯

  • 減少代碼體積,節(jié)省帶寬資源,提高資源加載速度

  • ......

而使用 express.js 或者 koa.js 開發(fā)的項(xiàng)目,并不存在這些問題。并且,Node.js 采用 CommonJS 模塊化規(guī)范,有緩存的機(jī)制;同時(shí),只有當(dāng)模塊在被用到時(shí),才會(huì)被導(dǎo)入。如果進(jìn)行打包,打包成一個(gè)文件,其實(shí)就浪費(fèi)了這個(gè)優(yōu)勢(shì)。所以針對(duì) node.js 項(xiàng)目,并不需要打包。

服務(wù)器安裝 Node.js

本文以 CentOS 系統(tǒng)為例進(jìn)行演示。

NVM

為了方便切換 node 的版本,我們使用 nvm 來管理 node。

Nvm(Node Version Manager) ,就是 Node.js 的版本管理工具。通過它,可以讓 node 在多個(gè)版本之間進(jìn)行任意切換,避免了需要切換版本時(shí)反復(fù)的下載和安裝的操作。

Nvm的官方倉(cāng)庫(kù)是 github.com/nvm-sh/nvm。因?yàn)樗陌惭b腳本存放在 githubusercontent 站點(diǎn)上,經(jīng)常訪問不了。所以我在 gitee 上新建了它的鏡像倉(cāng)庫(kù),這樣就能從 gitee 上訪問到它的安裝腳本了。

通過 curl 命令下載安裝腳本,并使用 bash 執(zhí)行腳本,會(huì)自動(dòng)完成 nvm 的安裝工作:

# curl -o- https://gitee.com/hsyq/nvm/raw/master/install.sh | bash復(fù)制代碼

當(dāng)安裝完成之后,我們?cè)俅蜷_一個(gè)新的窗口,來使用 nvm :

[root@ecs-221238 ~]# nvm -v0.39.1復(fù)制代碼

可以正常打印版本號(hào),說明 nvm 已經(jīng)安裝成功了。

安裝 Node.js

現(xiàn)在就可以使用 nvm 來安裝和管理 node 了。

查看可用的 node 版本:

# nvm ls-remote復(fù)制代碼

安裝 node:

# nvm install 18.0.0復(fù)制代碼

查看已經(jīng)安裝的 node 版本:

[root@ecs-221238 ~]# nvm list->      v18.0.0default -> 18.0.0 (-> v18.0.0)
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v18.0.0) (default)
stable -> 18.0 (-> v18.0.0) (default)復(fù)制代碼

選擇一個(gè)版本進(jìn)行使用:

# nvm use 18.0.0復(fù)制代碼

需要注意的一點(diǎn),在 Windows 上使用 nvm 時(shí),需要使用管理員權(quán)限執(zhí)行 nvm 命令。在 CentOS 上,我默認(rèn)使用 root 用戶登錄的,因而沒有出現(xiàn)問題。大家在使用時(shí)遇到了未知錯(cuò)誤,可以搜索一下解決方案,或者嘗試下是否是權(quán)限導(dǎo)致的問題。

在安裝 node 的時(shí)候,會(huì)自動(dòng)安裝 npm。查看 node 和 npm 的版本號(hào):

[root@ecs-221238 ~]# node -vv18.0.0[root@ecs-221238 ~]# npm -v8.6.0復(fù)制代碼

默認(rèn)的 npm 鏡像源是官方地址:

[root@ecs-221238 ~]# npm config get registryhttps://registry.npmjs.org/復(fù)制代碼

切換為國(guó)內(nèi)淘寶的鏡像源:

[root@ecs-221238 ~]# npm config set registry https://registry.npmmirror.com復(fù)制代碼

到此為止,服務(wù)器就已經(jīng)安裝好 node 環(huán)境和配置好 npm 了。

項(xiàng)目上傳到服務(wù)器

方法有很多,或者從 Github / GitLab / Gitee 倉(cāng)庫(kù)中下載到服務(wù)器中,或者本地通過 ftp 工具上傳。步驟很簡(jiǎn)單,不再演示。

演示項(xiàng)目放到了 /www 目錄 下:

Node多進(jìn)程模型和項(xiàng)目如何部署

服務(wù)器開放端口

一般云服務(wù)器僅開放了 22 端口用于遠(yuǎn)程登錄。而常用的80,443等端口并未開放。另外,我們準(zhǔn)備好的 express 項(xiàng)目運(yùn)行在3000端口上。所以需要先到云服務(wù)器的控制臺(tái)中,找到安全組,添加幾條規(guī)則,開放80和3000端口。

Node多進(jìn)程模型和項(xiàng)目如何部署

Node多進(jìn)程模型和項(xiàng)目如何部署

使用 PM2 管理應(yīng)用

在開發(fā)階段,我們可以使用 nodemon 來做實(shí)時(shí)監(jiān)聽和自動(dòng)重啟,提高開發(fā)效率。在生產(chǎn)環(huán)境,就需要祭出大殺器—PM2了。

基本使用

首先全局安裝 pm2:

# npm i -g pm2復(fù)制代碼

執(zhí)行 pm2 -v 命令查看是否安裝成功:

[root@ecs-221238 ~]# pm2 -v5.2.0復(fù)制代碼

切換到項(xiàng)目目錄,先把依賴裝上:

cd /www/express-demo
npm install復(fù)制代碼

然后使用 pm2 命令來啟動(dòng)應(yīng)用。

pm2 start app.js -i max// 或者pm2 start server.js -i 2復(fù)制代碼

PM2 管理應(yīng)用有 fork 和 cluster 兩種模式。在啟動(dòng)應(yīng)用時(shí),通過使用 -i 參數(shù)來指定實(shí)例的個(gè)數(shù),會(huì)自動(dòng)開啟 cluster 模式。此時(shí)就具備了負(fù)載均衡的能力。

-i :instance,實(shí)例的個(gè)數(shù)??梢詫懢唧w的數(shù)字,也可以配置成 max,PM2會(huì)自動(dòng)檢查可用的CPU的數(shù)量,然后盡可能多地啟動(dòng)進(jìn)程。

Node多進(jìn)程模型和項(xiàng)目如何部署

此時(shí)應(yīng)用就啟動(dòng)好了。PM2 會(huì)以守護(hù)進(jìn)程的形式管理應(yīng)用,這個(gè)表格展示了應(yīng)用運(yùn)行的一些信息,比如運(yùn)行狀態(tài),CPU使用率,內(nèi)存使用率等。

在本地的瀏覽器中訪問接口:

Node多進(jìn)程模型和項(xiàng)目如何部署

Cluster 模式是一個(gè)多進(jìn)程多實(shí)例的模型,請(qǐng)求進(jìn)來后會(huì)分配給其中一個(gè)進(jìn)程處理。正如前面我們看過的 cluster 模塊的用法一樣,由于 pm2 的守護(hù),即使某個(gè)進(jìn)程掛掉了,也會(huì)立刻重啟該進(jìn)程。

回到服務(wù)器終端,執(zhí)行 pm2 logs 命令,查看下 pm2 的日志:

Node多進(jìn)程模型和項(xiàng)目如何部署

可見,id 為1的應(yīng)用實(shí)例掛掉了,pm2 會(huì)立刻重啟該實(shí)例。注意,這里的 id 是應(yīng)用實(shí)例的 id,并非進(jìn)程 id。

到這里,一個(gè) express 項(xiàng)目的簡(jiǎn)單部署就完成了。通過使用 pm2 工具,基本能保證我們的項(xiàng)目可以穩(wěn)定可靠的運(yùn)行。

PM2 常用命令小結(jié)

這里整理了一些 pm2 工具常用的命令,可供查詢參考。

# Fork模式pm2 start app.js --name app # 設(shè)定應(yīng)用的名字為 app# Cluster模式# 使用負(fù)載均衡啟動(dòng)4個(gè)進(jìn)程pm2 start app.js -i 4     

# 將使用負(fù)載均衡啟動(dòng)4個(gè)進(jìn)程,具體取決于可用的 CPUpm2 start app.js -i 0   

# 等同于上面命令的作用pm2 start app.js -i max 

 # 給 app 擴(kuò)展額外的3個(gè)進(jìn)程pm2 scale app +3# 將 app 擴(kuò)展或者收縮到2個(gè)進(jìn)程pm2 scale app 2              # 查看應(yīng)用狀態(tài)# 展示所有進(jìn)程的狀態(tài)pm2 list  # 用原始 JSON 格式打印所有進(jìn)程列表pm2 jlist# 用美化的 JSON 打印所有進(jìn)程列表pm2 prettylist  # 展示特定進(jìn)程的所有信息pm2 describe 0# 使用儀表盤監(jiān)控所有進(jìn)程pm2 monit             

# 日志管理# 實(shí)時(shí)展示所有應(yīng)用的日志pm2 logs          # 實(shí)時(shí)展示 app 應(yīng)用的日志 pm2 logs app# 使用json格式實(shí)時(shí)展示日志,不輸出舊日志,只輸出新產(chǎn)生的日志pm2 logs --json# 應(yīng)用管理# 停止所有進(jìn)程pm2 stop all# 重啟所有進(jìn)程pm2 restart all       

# 停止指定id的進(jìn)程pm2 stop 0     

# 重啟指定id的進(jìn)程pm2 restart 0         

# 刪除id為0進(jìn)程pm2 delete 0# 刪除所有的進(jìn)程pm2 delete all         
復(fù)制代碼

每一條命令都可以親自嘗試一下,看看效果。

這里特別展示下 monit 命令,它可以在終端中啟動(dòng)一個(gè)面板,實(shí)時(shí)展示應(yīng)用的運(yùn)行狀態(tài),通過上下箭頭可以切換 pm2 管理的所有應(yīng)用:

Node多進(jìn)程模型和項(xiàng)目如何部署

進(jìn)階:使用 pm2 配置文件

PM2 的功能十分強(qiáng)大,遠(yuǎn)不止上面的這幾個(gè)命令。在真實(shí)的項(xiàng)目部署中,可能還需要配置日志文件,watch 模式,環(huán)境變量等等。如果每次都手敲命令是十分繁瑣的,所以 pm2 提供了配置文件來管理和部署應(yīng)用。

可以通過以下命令來生成一份配置文件:

[root@ecs-221238 express-demo]# pm2 init simpleFile /www/express-demo/ecosystem.config.js generated復(fù)制代碼

會(huì)生成一個(gè)ecosystem.config.js 文件:

module.exports = {
  apps : [{
    name   : "app1",
    script : "./app.js"
  }]
}復(fù)制代碼

也可以自己創(chuàng)建一個(gè)配置文件,比如 app.config.js

const path = require('path')module.exports = {  // 一份配置文件可以同時(shí)管理多個(gè) node.js 應(yīng)用
  // apps 是一個(gè)數(shù)組,每一項(xiàng)都是一個(gè)應(yīng)用的配置
  apps: [{
    // 應(yīng)用名稱
    name: "express-demo",

    // 應(yīng)用入口文件
    script: "./server.js",

    // 啟動(dòng)應(yīng)用的模式, 有兩種:cluster和fork,默認(rèn)是fork
    exec_mode: 'cluster',

    // 創(chuàng)建應(yīng)用實(shí)例的數(shù)量
    instances: 'max',

    // 開啟監(jiān)聽,當(dāng)文件變化后自動(dòng)重啟應(yīng)用
    watch: true,

    // 忽略掉一些目錄文件的變化。
    // 由于把日志目錄放到了項(xiàng)目路徑下,一定要將其忽略,否則應(yīng)用啟動(dòng)產(chǎn)生日志,pm2 監(jiān)聽到變化就會(huì)重啟,重啟又產(chǎn)生日志,就會(huì)進(jìn)入死循環(huán)
    ignore_watch: [
      "node_modules",
      "logs"
    ],
    // 錯(cuò)誤日志存放路徑
    err_file: path.resolve(__dirname, 'logs/error.log'),

    // 打印日志存放路徑
    out_file: path.resolve(__dirname, 'logs/out.log'),

    // 設(shè)置日志文件中每條日志前面的日期格式
    log_date_format: "YYYY-MM-DD HH:mm:ss",
  }]
}復(fù)制代碼

讓 pm2 使用配置文件來管理 node 應(yīng)用:

pm2 start app.config.js復(fù)制代碼

現(xiàn)在 pm2 管理的應(yīng)用,會(huì)將日志放到項(xiàng)目目錄下(默認(rèn)是放到 pm2 的安裝目錄下),并且能監(jiān)聽文件的變化,自動(dòng)重啟服務(wù)。

Node多進(jìn)程模型和項(xiàng)目如何部署

更多有用的配置可以參考 PM2 官方文檔,點(diǎn)此訪問。

Nginx 代理轉(zhuǎn)發(fā)接口

上面我們直接將 nodejs 項(xiàng)目的3000端口暴露了出去。一般我們都會(huì)使用 nginx 做一個(gè)代理轉(zhuǎn)發(fā),只對(duì)外暴露 80 端口。

安裝 Nginx

首先服務(wù)器中需要安裝 nginx ,有三種方式:

  • 下載源碼編譯安裝

  • 使用 docker 安裝

  • 使用包管理工具安裝

我這里的系統(tǒng)是 CentOS 8,已經(jīng)更換了可用的 yum 源,可以直接安裝 nginx。如果你的操作系統(tǒng)為 CentOS 7 或者其他發(fā)行版,可以搜索適合的安裝方法。

使用 yum 安裝:

# yum install -y nginx復(fù)制代碼

然后啟動(dòng) nginx:

# systemctl start nginx復(fù)制代碼

打開瀏覽器訪問服務(wù)器地址,可以看到 nginx 默認(rèn)的主頁(yè):

Node多進(jìn)程模型和項(xiàng)目如何部署

配置接口轉(zhuǎn)發(fā)

為項(xiàng)目新建一個(gè)配置文件:

# vim /etc/nginx/conf.d/express.conf復(fù)制代碼

監(jiān)聽80端口,將所有請(qǐng)求轉(zhuǎn)發(fā)給服務(wù)器本地的3000端口的程序處理:

server {
    listen       80;
    server_name  ironfan.site;
    location / {
          proxy_pass http://localhost:3000;
    }
}復(fù)制代碼

conf 目錄下的配置文件,會(huì)被主配置文件 /etc/nginx/nginx.conf 加載:

Node多進(jìn)程模型和項(xiàng)目如何部署

修改完配置文件,一定要重啟服務(wù):

# systemctl restart nginx復(fù)制代碼

然后本地打開瀏覽器,去掉原來的3000端口號(hào),直接訪問完整的 url:

Node多進(jìn)程模型和項(xiàng)目如何部署

到這里,就完成了接口轉(zhuǎn)發(fā)的配置。從用戶的角度出發(fā),這個(gè)也叫反向代理。

關(guān)于“Node多進(jìn)程模型和項(xiàng)目如何部署”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI