pm2實踐指南
PM2是一個帶有負載均衡功能的Node應用的程序管理器。PM2可以利用伺服器上的所有CPU,並保證程序永遠都活著,0秒的過載,部署管理多個Node專案。PM2是Node線上部署完美的管理工具
基本指令
npm install pm2 -g : 全域性安裝。 pm2 start app.js : 啟動服務,入口檔案是app.js。 pm2 start app.js -i [n] --name [name] : 啟動n個程序,名字命名為name。 npm restart[name or id] : 重啟服務。 npm reload[name or id] : 和rastart功能相同,但是可以實現0s的無縫銜接;如果有nginx的使用經驗,可以 對比nginx reload指令。 pm2 start app.js --max_memory_restart 1024M : 當記憶體超過1024M時自動重啟。 如果工程中有比較棘手的內 存洩露問題,這個算是一個折中方案。 pm2 monit : 對服務進行監控。 複製程式碼
檢視服務程序數
至於要啟動幾個程序,可以通過伺服器的核心數進行確定,幾個核心就啟動幾個服務。指令如下:
# 檢視物理CPU個數 cat /proc/cpuinfo| grep "physical id" | sort| uniq | wc -l # 檢視每個物理CPU中core的個數(即核數) cat /proc/cpuinfo| grep "cpu cores"| uniq # 檢視邏輯CPU的個數 cat /proc/cpuinfo| grep "processor"| wc -l 複製程式碼
當然可以啟動多個埠,一個埠號對應一個服務,這樣的話就需要nignx來做負載均衡了。
fork與cluster啟動模式
開發環境中多以fork的方式啟動,生產環境中多用cluster方式啟動

上面的示例圖中可以看一“watching”一項,這個項預設是disabled,可以通過如下命令開啟
pm2 start app.js --name m --watch 複製程式碼
建議:這個適合在開發時用,可以省不少時間,生產環境下最好不要用
1、cluster是fork的派生,cluster支援所有cluster擁有的特性;
2、fork不支援socket地址埠複用,cluster支援地址埠複用。因為只有node的cluster模組支援socket選項SO_REUSEADDR;
fork不可以啟動多個例項程序,cluster可以啟動多個例項。但node的child_process.fork是可以實現啟動多個程序的,但是為什麼沒有實現呢?就個人理解,node多為提供網路服務,啟動多個例項需要地址埠複用,此時便可使用cluster模式實現,但fork模式並不支援地址埠複用,多例項程序啟動會產生異常錯誤。但對於常駐任務指令碼而言,不需要提供網路服務,此時多程序啟動可以實現,同時也提高了任務處理效率。對於上述需求,可以兩種方式實現,一是配置app0,app1,app2方式啟動多個程序,二是通過應用例項自身呼叫child_process.fork多程序程式設計實現;
fork模式可以應用於其他語言,如php,python,perl,ruby,bash,coffee, 而cluster只能應用於node;
fork不支援定時重啟,cluster支援定時重啟。定時重啟也就是配置中的cron_restart配置項。
pm2的監控
pm2的監控有兩種方式:
cli方式監控
pm2 monit是專門用來監控的命令,監控項包括cpu與記憶體,缺點monit展示內容太過粗糙,不夠詳細

pm2 list展示當前所有pm2的管理專案

可以查看出每個程序的執行狀態。
如果需要更詳細的監控內容,對於cli而言一般都是可以實現的。
這種監控方式的缺點:
1、不夠直觀,需要自己去執行命令並分析結果;
2、不便於多臺伺服器的應用監控管理;
日誌問題
日誌系統對於任意應用而言,通常都是必不可少的一個輔助功能。pm2的相關檔案預設存放 於$HOME/.pm2/
目錄下,其日誌主要有兩類:

1、 pm2自身的日誌,存放於 $HOME/.pm2/pm2.log
;
2、 pm2所管理的應用的日誌,存放於 $HOME/.pm2/logs/
目錄下,標準誰出日誌存放於 ${APP_NAME}_out.log
,標準錯誤日誌存放於${APP_NAME}_error.log;
這裡之所以把日誌單獨說明一下是因為,如果程式開發不嚴謹,為了除錯程式,導致應用產生大量標準輸出,使伺服器本身記錄大量的日誌,導致服務磁碟滿載問題。一般而言,pm2管理的應用本身都有自己日誌系統,所以對於這種不必要的輸出內容需禁用日誌,重定向到 /dev/null
。
與crontab比較,也有類似情況,crontab自身日誌,與其管理的應用本身的輸出。應用指令碼輸出一定需要重定向到/dev/null,因為該輸出內容會以郵件的形式傳送給使用者,內容儲存在郵件檔案,會產生意向不到的結果,或會導致指令碼壓根不被執行。
高階用法
pm2支援配置檔案啟動:
pm2 pm2
: 生成配置檔案ecosystem.json
pm2 startOrRestart /file/path/pm2.json
: 通過配置檔案啟動服務
如下是開發時pm2.json的內容
{ /** * Application configuration section * http://pm2.keymetrics.io/docs/usage/application-declaration/ * 多個服務,依次放到apps對應的數組裡 */ apps : [ // First application { "name": "alumni2.0", "max_memory_restart": "300M", "cwd": "./", "script": "./app.js", "log_date_format": "YYYY-MM-DD HH:mm Z", "error_file": "./log/app-err.log", "out_file": "./log/app-out.log", "pid_file": "./log/node.pid", "instances": 6, "min_uptime": "60s", "max_restarts": 30, "watch": false } ] } 複製程式碼
上述採用cluster模式啟動了6個服務程序;如果服務佔用的記憶體超過300M,會自動進行重啟。
配置項
name 應用程序名稱; script 啟動指令碼路徑; cwd 應用啟動的路徑,關於script與cwd的區別舉例說明:在/home/polo/目錄下執行/data/release/node/ index.js,此處script為/data/release/node/index.js,cwd為/home/polo/; args 傳遞給指令碼的引數; interpreter 指定的指令碼直譯器; interpreter_args 傳遞給直譯器的引數; instances 應用啟動例項個數,僅在cluster模式有效,預設為fork; exec_mode 應用啟動模式,支援fork和cluster模式; watch 監聽重啟,啟用情況下,資料夾或子資料夾下變化應用自動重啟; ignore_watch 忽略監聽的資料夾,支援正則表示式; max_memory_restart 最大記憶體限制數,超出自動重啟; env 環境變數,object型別,如{"NODE_ENV":"production", "ID": "42"}; log_date_format 指定日誌日期格式,如YYYY-MM-DD HH:mm:ss; error_file 記錄標準錯誤流,$HOME/.pm2/logs/XXXerr.log),程式碼錯誤可在此檔案查詢; out_file 記錄標準輸出流,$HOME/.pm2/logs/XXXout.log),如應用列印大量的標準輸出,會導致pm2日誌過大; min_uptime 應用執行少於時間被認為是異常啟動; max_restarts 最大異常重啟次數,即小於min_uptime執行時間重啟次數; autorestart 預設為true, 發生異常的情況下自動重啟; cron_restart crontab時間格式重啟應用,目前只支援cluster模式; force 預設false,如果true,可以重複啟動一個指令碼。pm2不建議這麼做; restart_delay 異常重啟情況下,延時重啟時間; 複製程式碼
穩定執行建議
PM2是一款非常優秀的Node程序管理工具,它有著豐富的特性:能夠充分利用多核CPU且能夠負載均衡、能夠幫助應用在崩潰後、指定時間(cluster model)和超出最大記憶體限制等情況下實現自動重啟。
個人幾點看法保證常駐應用程序穩定執行:
1、定時重啟,應用程序執行時間久了或許總會產生一些意料之外的問題,定時可以規避一些不可測的情況;
2、最大記憶體限制,根據觀察設定合理記憶體限制,保證應用異常執行;
3、合理min_uptime,min_uptime是應用正常啟動的最小持續執行時長,超出此時間則被判定為異常啟動;
4、設定異常重啟延時restart_delay,對於異常情況導致應用停止,設定異常重啟延遲可防止應用在不可測情況下不斷重啟的導致重啟次數過多等問題;
5、設定異常重啟次數,如果應用不斷異常重啟,並超過一定的限制次數,說明此時的環境長時間處於不可控狀態,伺服器異常。此時便可停止嘗試,發出錯誤警告通知等。
關於pm2的使用,主要還是運用於常駐指令碼。