使用PM2實(shí)現(xiàn)高效的應(yīng)用監(jiān)控與管理功能
1. pm2
PM2 是一個(gè)流行的進(jìn)程管理器,用于 Node.js 應(yīng)用程序。它支持應(yīng)用程序的負(fù)載均衡、自動(dòng)重啟、日志管理、監(jiān)控以及多環(huán)境管理等功能。PM2讓開發(fā)者能夠以守護(hù)進(jìn)程的方式運(yùn)行和管理 Node.js 應(yīng)用,即使在應(yīng)用崩潰或服務(wù)器重啟后也能自動(dòng)重啟應(yīng)用。這使得 PM2非常適合在生產(chǎn)環(huán)境中部署 Node.js 應(yīng)用。除此之外,PM2還支持應(yīng)用的零停機(jī)更新,以及對(duì) Docker 容器的支持。
2. 誕生背景
PM2 的誕生背景主要是為了解決 Node.js 應(yīng)用程序在生產(chǎn)環(huán)境中的運(yùn)維問(wèn)題。在 PM2出現(xiàn)之前,Node.js 開發(fā)者經(jīng)常面臨如何有效管理和維持應(yīng)用穩(wěn)定運(yùn)行的挑戰(zhàn),特別是在應(yīng)對(duì)應(yīng)用崩潰、服務(wù)器重啟或是負(fù)載均衡等方面。
PM2的主要目標(biāo)是提供一個(gè)簡(jiǎn)單而強(qiáng)大的工具,幫助開發(fā)者和系統(tǒng)管理員在生產(chǎn)環(huán)境中管理和維護(hù) Node.js 應(yīng)用。它解決的關(guān)鍵問(wèn)題包括:
- 自動(dòng)重啟: 如果 Node.js 應(yīng)用崩潰或由于某種原因停止,PM2可以自動(dòng)重啟應(yīng)用,確保服務(wù)的持續(xù)可用性。
- 負(fù)載均衡: PM2支持集群模式,能夠啟動(dòng)多個(gè)應(yīng)用實(shí)例,并在它們之間自動(dòng)分配負(fù)載,提高應(yīng)用的可伸縮性和可用性。
- 無(wú)停機(jī)更新: PM2允許開發(fā)者在不停止當(dāng)前服務(wù)的情況下,更新 Node.js 應(yīng)用到新的版本,這對(duì)于需要24/7運(yùn)行的服務(wù)來(lái)說(shuō)非常重要。
- 日志管理: PM2提供了日志管理的功能,使得跟蹤和調(diào)試生產(chǎn)環(huán)境中的應(yīng)用更為便捷。
- 監(jiān)控: PM2包含了一個(gè)監(jiān)控系統(tǒng),可以實(shí)時(shí)查看應(yīng)用的 CPU 和內(nèi)存使用情況,幫助開發(fā)者優(yōu)化應(yīng)用性能。
3. 安裝
執(zhí)行以下命令來(lái)全局安裝 PM2。全局安裝意味著你可以在任何地方運(yùn)行 PM2命令。
npm install pm2 -g
這條命令會(huì)將 PM2安裝到你的系統(tǒng)上,-g
參數(shù)表示全局安裝,這樣你就可以在任何目錄下使用 PM2命令。
安裝完成后,你可以運(yùn)行以下命令來(lái)檢查 PM2是否正確安裝:
pm2 --version
4. 常用命令
命令 | 描述 | 使用示例及參數(shù) |
---|---|---|
start | 啟動(dòng)應(yīng)用 | pm2 start app.js pm2 start app.js -i 4 --name myApp pm2 start app.js --watch |
stop | 停止應(yīng)用 | pm2 stop app.js pm2 stop 0 pm2 stop all |
restart | 重啟應(yīng)用 | pm2 restart app.js pm2 restart all |
delete | 刪除應(yīng)用 | pm2 delete app.js pm2 delete 0 pm2 delete all |
list | 列出所有應(yīng)用 | pm2 list |
monit | 監(jiān)控應(yīng)用 | pm2 monit |
logs | 查看應(yīng)用日志 | pm2 logs pm2 logs app.js pm2 logs --lines 100 |
save | 保存當(dāng)前應(yīng)用列表 | pm2 save |
reload | 重載應(yīng)用 | pm2 reload app.js pm2 reload all |
scale | 調(diào)整集群模式下的實(shí)例數(shù)量 | pm2 scale app +1 pm2 scale app 4 |
describe | 查看應(yīng)用詳細(xì)信息 | pm2 describe 0 |
update | 更新 PM2守護(hù)進(jìn)程 | pm2 update |
status | 查看應(yīng)用狀態(tài) | pm2 status |
flush | 清空所有日志文件 | pm2 flush |
startup | 創(chuàng)建開機(jī)自啟動(dòng)腳本 | pm2 startup |
unstartup | 刪除開機(jī)自啟動(dòng)腳本 | pm2 unstartup |
5. 配置文件
PM2的配置文件通常被稱為ecosystem.config.js
,這是一個(gè) JavaScript 文件,允許你配置和管理應(yīng)用程序的多個(gè)方面。通過(guò)使用配置文件,你可以輕松地指定環(huán)境變量、日志文件路徑、實(shí)例數(shù)量等,并且可以一次性啟動(dòng)多個(gè)應(yīng)用。下面詳細(xì)介紹如何使用 PM2配置文件。
基本結(jié)構(gòu)
PM2的ecosystem.config.js
文件基本結(jié)構(gòu)如下:
module.exports = { apps: [ { name: "app1", // 應(yīng)用程序名稱 script: "./app.js", // 主腳本路徑 args: "arg1 arg2", // 傳遞給腳本的參數(shù) instances: 4, // 應(yīng)用實(shí)例數(shù) autorestart: true, // 自動(dòng)重啟 watch: false, // 監(jiān)控文件變動(dòng) max_memory_restart: "1G", // 內(nèi)存超過(guò)1G 重啟 env: { // 環(huán)境變量 NODE_ENV: "development", }, env_production: { // 生產(chǎn)環(huán)境變量 NODE_ENV: "production", }, }, { name: "app2", script: "./app2.js", // 其他配置... }, ], };
主要字段解釋
- apps: 一個(gè)數(shù)組,包含了你要運(yùn)行的應(yīng)用的配置對(duì)象。
- name: 應(yīng)用程序的名稱。
- script: 應(yīng)用程序的啟動(dòng)腳本或文件。
- args: 傳遞給腳本的參數(shù)。
- instances: 啟動(dòng)應(yīng)用實(shí)例的數(shù)量。對(duì)于無(wú)狀態(tài)的應(yīng)用,可以設(shè)置為
max
以根據(jù) CPU 核心數(shù)量來(lái)啟動(dòng)最大實(shí)例數(shù)。 - autorestart: 如果應(yīng)用崩潰或者停止,是否自動(dòng)重啟。
- watch: 是否啟用文件監(jiān)控和自動(dòng)重啟。
- max_memory_restart: 當(dāng)應(yīng)用超過(guò)指定內(nèi)存量時(shí)自動(dòng)重啟。
- env: 在這個(gè)對(duì)象中,你可以指定傳遞給應(yīng)用的環(huán)境變量。這些環(huán)境變量在所有環(huán)境下都會(huì)加載。
- env_production, env_development: 你可以為不同的環(huán)境指定不同的環(huán)境變量。
使用配置文件
- 啟動(dòng)應(yīng)用: 使用配置文件啟動(dòng)應(yīng)用時(shí),運(yùn)行如下命令:
pm2 start ecosystem.config.js
- 指定環(huán)境: 如果你有為不同環(huán)境定義的變量,可以在啟動(dòng)時(shí)指定:
pm2 start ecosystem.config.js --env production
配置文件為應(yīng)用部署提供了強(qiáng)大而靈活的管理方式,特別是當(dāng)你需要部署多個(gè)應(yīng)用或需要為應(yīng)用指定特定的環(huán)境變量和配置時(shí)。通過(guò)精心設(shè)計(jì)的配置文件,你可以確保應(yīng)用的部署更加一致和可預(yù)測(cè)。
6. CLI 實(shí)現(xiàn)配置文件效果
如果你不使用配置文件,而是選擇直接使用 PM2的 CLI 命令來(lái)實(shí)現(xiàn)上面提到的功能,可以通過(guò)在命令行中添加特定的選項(xiàng)和參數(shù)來(lái)完成。下面是如何通過(guò) CLI 命令實(shí)現(xiàn)配置文件中提到的一些主要功能:
啟動(dòng)應(yīng)用并傳遞參數(shù):
pm2 start app.js --name "app1" -- arg1=value1 arg2=value2
這里
--name "app1"
設(shè)定了應(yīng)用的名稱,-- arg1 arg2
向應(yīng)用傳遞了參數(shù)。指定實(shí)例數(shù)量:
pm2 start app.js -i 4
該命令啟動(dòng)了4個(gè)應(yīng)用實(shí)例。如果你想要根據(jù) CPU 核心數(shù)量來(lái)啟動(dòng)最大實(shí)例數(shù),可以使用
-i max
。啟用自動(dòng)重啟: 自動(dòng)重啟是 PM2的默認(rèn)行為,無(wú)需特別指定。
啟用文件監(jiān)控:
pm2 start app.js --watch
這會(huì)監(jiān)控應(yīng)用目錄中文件的變動(dòng),并在變動(dòng)時(shí)自動(dòng)重啟應(yīng)用。
限制內(nèi)存重啟:
pm2 start app.js --max-memory-restart 1G
當(dāng)應(yīng)用消耗的內(nèi)存超過(guò)1GB 時(shí),PM2將自動(dòng)重啟應(yīng)用。
設(shè)置環(huán)境變量: 你可以在啟動(dòng)命令中直接設(shè)置環(huán)境變量:
NODE_ENV=development pm2 start app.js
或者,為了同時(shí)設(shè)置多個(gè)環(huán)境變量,可以使用:
pm2 start app.js --env NODE_ENV=development,env1=13,env2=32
使用 CLI 命令直接設(shè)置這些選項(xiàng)的好處是快速簡(jiǎn)便,特別是對(duì)于一次性或臨時(shí)的任務(wù)。但對(duì)于更復(fù)雜的部署,或者當(dāng)你需要在多個(gè)環(huán)境中維護(hù)一致的配置時(shí),使用配置文件將更為有效和易于管理。
7. 監(jiān)控
PM2提供了一個(gè)內(nèi)置的監(jiān)控工具,允許你實(shí)時(shí)查看運(yùn)行在 PM2下的應(yīng)用的性能指標(biāo),如 CPU 和內(nèi)存使用情況。這個(gè)監(jiān)控工具可以幫助你了解應(yīng)用的運(yùn)行狀況,及時(shí)發(fā)現(xiàn)潛在的問(wèn)題。
使用 PM2監(jiān)控命令行工具
- 啟動(dòng)監(jiān)控控制臺(tái): 要查看實(shí)時(shí)的監(jiān)控?cái)?shù)據(jù),可以在命令行中使用以下命令:
pm2 monit
- 這會(huì)打開一個(gè)交互式的監(jiān)控控制臺(tái),其中展示了所有由 PM2管理的進(jìn)程的 CPU 和內(nèi)存使用情況。
使用 PM2 Web 界面
PM2還提供了一個(gè) Web 界面,稱為 PM2 Plus,用于更高級(jí)的監(jiān)控和管理功能,包括遠(yuǎn)程監(jiān)控和日志管理。不過(guò),這需要在 PM2 Plus 網(wǎng)站上注冊(cè)并設(shè)置 keymetrics 代理。
- PM2 Plus:
- 你可以訪問(wèn)PM2 Plus來(lái)獲取更多關(guān)于這個(gè)服務(wù)的信息。
- 它允許你監(jiān)控關(guān)鍵指標(biāo),設(shè)置告警,查看日志,和進(jìn)行實(shí)時(shí)的問(wèn)題排查。
自定義指標(biāo)
PM2還允許你定義自己的指標(biāo)來(lái)監(jiān)控。你可以在你的應(yīng)用中集成 PM2的 API 來(lái)發(fā)送自定義指標(biāo),這樣就可以在 PM2的監(jiān)控工具中查看這些指標(biāo)了。
8. 其它
8.1 負(fù)載均衡下的會(huì)話管理
在使用 PM2的集群模式運(yùn)行多個(gè)實(shí)例的場(chǎng)景下,確保會(huì)話(session)一致性是一個(gè)重要的考慮點(diǎn)。由于每個(gè)實(shí)例都是獨(dú)立運(yùn)行的,直接在內(nèi)存中存儲(chǔ)會(huì)話信息可能會(huì)導(dǎo)致會(huì)話不一致的問(wèn)題,因?yàn)橛脩舻暮罄m(xù)請(qǐng)求可能被路由到不同的實(shí)例上,而不同的實(shí)例之間無(wú)法共享內(nèi)存中的會(huì)話信息。
為了解決這個(gè)問(wèn)題,通常的做法是使用一個(gè)中央存儲(chǔ)來(lái)存儲(chǔ)會(huì)話信息,這樣不同的實(shí)例可以共享這些信息。以下是一些常見的解決方案:
使用 Redis 存儲(chǔ)會(huì)話: Redis 是一種常用的解決方案,它提供了快速的數(shù)據(jù)讀寫并支持?jǐn)?shù)據(jù)持久化。使用 Redis 作為會(huì)話存儲(chǔ),可以確保不同的實(shí)例能夠訪問(wèn)和更新同一份會(huì)話數(shù)據(jù)。
使用數(shù)據(jù)庫(kù)存儲(chǔ)會(huì)話: 另一種常見的方法是將會(huì)話存儲(chǔ)在數(shù)據(jù)庫(kù)中,如 MongoDB 或 MySQL 等。這樣可以確保會(huì)話信息的一致性,但可能比使用內(nèi)存存儲(chǔ)或 Redis 的性能稍低。
使用其他共享存儲(chǔ)方案: 根據(jù)應(yīng)用的具體需求,還可以考慮使用其他類型的共享存儲(chǔ)方案,如 Memcached、Etcd 等。
對(duì)于 Node.js 應(yīng)用,如果你使用 Express 框架,可以利用express-session
配合 Redis 等存儲(chǔ)的中間件來(lái)實(shí)現(xiàn)會(huì)話的共享。例如,使用connect-redis
中間件將會(huì)話存儲(chǔ)在 Redis 中:
const session = require("express-session"); const RedisStore = require("connect-redis")(session); app.use( session({ store: new RedisStore({ // Redis 服務(wù)器配置 host: "localhost", port: 6379, }), secret: "your_secret", resave: false, saveUninitialized: false, }) );
使用這種方式,無(wú)論用戶的請(qǐng)求被路由到哪個(gè)實(shí)例,應(yīng)用都能訪問(wèn)到同一份會(huì)話信息,從而避免了會(huì)話不一致的問(wèn)題。確保你的會(huì)話存儲(chǔ)方案是可伸縮的,并且可以處理你的應(yīng)用負(fù)載。
8.2 異常重啟處理
當(dāng) PM2重啟應(yīng)用時(shí),確保應(yīng)用的當(dāng)前狀態(tài)完成后再繼續(xù),以及在異常重啟下恢復(fù)重啟前的狀態(tài),需要在應(yīng)用層面做一些策略設(shè)計(jì)。這通常涉及到優(yōu)雅的關(guān)閉處理和持久化狀態(tài)管理。
優(yōu)雅的關(guān)閉處理
捕獲關(guān)閉信號(hào):在 Node.js 應(yīng)用中,你可以監(jiān)聽如
SIGINT
和SIGTERM
這樣的信號(hào),這樣當(dāng) PM2嘗試重啟應(yīng)用時(shí),你的代碼可以捕獲這些信號(hào)并執(zhí)行清理邏輯。
process.on("SIGINT", function () { console.log("Received SIGINT. Performing graceful shutdown."); gracefulShutdown(); }); function gracefulShutdown() { // 在這里執(zhí)行清理操作,如關(guān)閉數(shù)據(jù)庫(kù)連接、完成正在處理的請(qǐng)求等 }
完成正在處理的請(qǐng)求:在收到關(guān)閉信號(hào)后,應(yīng)用應(yīng)該停止接受新的請(qǐng)求,但同時(shí)確保當(dāng)前正在處理的請(qǐng)求完成。這可能涉及到跟蹤所有活躍的請(qǐng)求并等待它們結(jié)束。
恢復(fù)狀態(tài)
狀態(tài)持久化:為了在重啟后恢復(fù)狀態(tài),應(yīng)用的關(guān)鍵狀態(tài)需要持久化,例如存儲(chǔ)在數(shù)據(jù)庫(kù)或文件系統(tǒng)中。這樣,在應(yīng)用重啟后,可以從這些持久化的存儲(chǔ)中恢復(fù)狀態(tài)。
啟動(dòng)時(shí)的狀態(tài)恢復(fù)邏輯:應(yīng)用啟動(dòng)時(shí)應(yīng)該包含邏輯來(lái)檢查并恢復(fù)之前的狀態(tài)。這可能包括讀取數(shù)據(jù)庫(kù)中的數(shù)據(jù),或從文件系統(tǒng)中恢復(fù)信息等。
PM2特定策略
進(jìn)程守護(hù):PM2會(huì)守護(hù)你的應(yīng)用進(jìn)程,如果應(yīng)用崩潰或非正常退出,它會(huì)自動(dòng)重啟應(yīng)用。這是通過(guò)配置 PM2的
restart
策略實(shí)現(xiàn)的。零停機(jī)重啟:使用 PM2的
reload
或gracefulReload
命令可以實(shí)現(xiàn)零停機(jī)重啟,這對(duì)于不間斷服務(wù)的應(yīng)用特別有用。這些命令會(huì)等待新的實(shí)例啟動(dòng)并接收連接后,再停止舊的實(shí)例。
8.3 SIGINT 信號(hào)超時(shí)處理
const express = require("express"); const app = express(); const server = app.listen(3000, () => console.log("Server started on port 3000") ); let activeConnections = new Set(); app.get("/", (req, res) => { // 模擬長(zhǎng)時(shí)間運(yùn)行的請(qǐng)求 const requestId = Date.now(); activeConnections.add(requestId); console.log(`Request ${requestId} started`); setTimeout(() => { res.send("Hello World"); activeConnections.delete(requestId); console.log(`Request ${requestId} finished`); }, 10000); // 假設(shè)請(qǐng)求處理需要10秒 }); process.on("SIGINT", () => { console.log("Received SIGINT. Graceful shutdown start."); // 停止服務(wù)器接受新的連接 server.close(() => { console.log("Server closed. No new connections are accepted."); }); // 等待所有活動(dòng)請(qǐng)求完成 const checkActiveConnections = () => { if (activeConnections.size > 0) { console.log( `Waiting for ${activeConnections.size} active connections to finish.` ); setTimeout(checkActiveConnections, 1000); } else { console.log("All connections finished. Exiting now."); process.exit(0); } }; checkActiveConnections(); });
捕獲SIGINT
信號(hào)后,進(jìn)程確實(shí)有機(jī)會(huì)執(zhí)行清理邏輯,但這并不意味著 PM2無(wú)法再去主動(dòng) kill 進(jìn)程。當(dāng)你的應(yīng)用捕獲SIGINT
信號(hào)并進(jìn)入清理階段時(shí),PM2會(huì)等待一段時(shí)間(默認(rèn)是1600毫秒),這個(gè)時(shí)間是可配置的。如果應(yīng)用在這段時(shí)間內(nèi)沒(méi)有退出,PM2會(huì)發(fā)送SIGKILL
信號(hào)來(lái)強(qiáng)制終止進(jìn)程。
這意味著你的清理邏輯需要在 PM2的超時(shí)時(shí)間內(nèi)完成,以確保它能夠正常執(zhí)行并讓進(jìn)程優(yōu)雅地退出。如果清理邏輯需要的時(shí)間超過(guò)了 PM2的超時(shí)閾值,你可以調(diào)整 PM2的配置來(lái)增加這個(gè)超時(shí)時(shí)間。
例如,你可以在啟動(dòng)應(yīng)用時(shí)通過(guò)--kill-timeout
參數(shù)來(lái)設(shè)置這個(gè)超時(shí)時(shí)間:
pm2 start app.js --kill-timeout 3000
這里,--kill-timeout 3000
表示 PM2將等待3000毫秒(3秒)給應(yīng)用足夠的時(shí)間來(lái)處理清理邏輯。如果應(yīng)用在3秒內(nèi)沒(méi)有退出,PM2將使用SIGKILL
來(lái)強(qiáng)制終止應(yīng)用。
這個(gè)機(jī)制確保了你的應(yīng)用有機(jī)會(huì)在 PM2重啟或停止它之前完成必要的清理工作,同時(shí)也保留了 PM2在應(yīng)用無(wú)法正確響應(yīng)終止信號(hào)時(shí)強(qiáng)制關(guān)閉它的能力。
以上就是使用PM2實(shí)現(xiàn)高效的應(yīng)用監(jiān)控與管理功能的詳細(xì)內(nèi)容,更多關(guān)于PM2應(yīng)用監(jiān)控與管理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Node.js中讀取TXT文件內(nèi)容fs.readFile()用法
在本篇文章中我們給大家分享一下Node.js中讀取TXT文件內(nèi)容以及fs.readFile()的用法,需要的朋友們可以參考下。2018-10-10nodejs實(shí)例解析(輸出hello world)
本文主要介紹nodejs實(shí)例解析:輸出hello world的完整過(guò)程。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-01-01nodejs+express實(shí)現(xiàn)文件上傳下載管理網(wǎng)站
這篇文章主要為大家詳細(xì)介紹了nodejs+express實(shí)現(xiàn)文件上傳下載管理的網(wǎng)站,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03node封裝一個(gè)控制臺(tái)進(jìn)度條插件???????詳情
這篇文章主要介紹了node封裝一個(gè)控制臺(tái)進(jìn)度條插件???????詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08