對於后台進程的管理,常用的工具是crontab,可用於兩種場景:定時任務和常駐腳本。關於常駐腳本,今天介紹一款更好用的工具:pm2,基於nodejs開發的進程管理器,適用於后台常駐腳本管理,同時對node網絡應用有自建負載均衡功能。官方的說法,pm2 是一個帶有負載均衡功能的Node應用的進程管理器,個人認為,並不准確,因為pm2支持多種語言,只是對於除node之外的其他進程無負載均衡的能力。
一,pm2特點:
說一些pm2有哪些優點好處呢?
-
支持進程行為配置 ,即可以通過配置,實現對pm2管理應用的一些基礎屬性更新修改,如應用名稱,啟動模式等;
-
支持集群模式,支持負載均衡,但因采用nodejs的cluster模塊實現,僅適用於nodejs進程;
-
支持source map,此項針對js, source map文件是js源文件的信息文件,里面存儲着源文件的位置信息;
-
支持熱重啟;
-
支持部署工作流,pm2可依據測試環境和線上環境自動部署到不同的服務器,同時運行在不同配置下;
-
支持監聽重啟,在文件更新等情況下可實現進程自動重啟;
-
支持linux的startup進程啟動,startup是指系統boot, 進程自啟動,如centos的chkconfig;
-
日志管理,兩種日志,pm2系統日志與管理的進程日志,默認會把進程的控制台輸出記錄到日志中;
-
命令自動補全功能,個人感覺這個功能意義不大,而且嘗試了一下,沒有原生的linux命令自動補全反應敏捷;
-
監控功能,pm2 monit監控cpu和memory使用情況,keymetrics監控更為詳細;
-
支持開發調試模式,非后台運行,pm2-dev start <appName>;
-
支持pm2模塊開發,實現pm2的功能擴展;
-
keymetrics監控,比pm2 monit監控更為詳細友好,通過web頁面展示;
-
最大內存重啟,設置最大內存限制,超過限制自動重啟;
-
編程API,提供API供開發者通過編程方式靈活管理進程;
以上簡要概述了pm2進程管理工具的特點。
二,pm2常用命令
常用命令通常都是比較簡單。下面列舉一些pm2常用的管理命令
-
pm2 start <script_file|config_file> [options] 啟動指定應用,如pm2 start index.js --name httpServer;
-
pm2 stop <appName> [options] 停止指定應用,如pm2 stop httpServer;
-
pm2 reload|restart <appName> [options] 重啟指定應用,如pm2 restart httpServer;
-
pm2 show <appName> [options] 顯示指定應用詳情,如pm2 show httpServer;
-
pm2 delete <appName> [options] 刪除指定應用,如pm2 delete httpServer,如果修改應用配置行為,最好先刪除應用后,重新啟動方才生效,如修改腳本入口文件;
-
pm2 kill 殺掉pm2管理的所有進程;
-
pm2 logs <appName> 查看指定應用的日志,即標准輸出和標准錯誤;
-
pm2 monit 監控各個應用進程cpu和memory使用情況;
三,pm2常用配置
pm2 配置方式
-
命令行方式
pm2 start index.js --name HttpServer --interpreter node
此處通過命令的選項配置應用名稱為httpServer,index.js腳本文件解釋器為node,更多選項可查看pm2 --help獲取;
-
配置文件方式
pm2配置文件方式支持yml與json格式
processes.yml文件
-
apps: - script : ./api.js name : 'api-app' instances: 4 exec_mode: cluster - script : ./worker.js name : 'worker' watch : true env : NODE_ENV: development env_production: NODE_ENV: production
processes.json
-
{ apps : [{ name : "worker", script : "./worker.js", watch : true, env: { "NODE_ENV": "development", }, env_production : { "NODE_ENV": "production" } },{ name : "api-app", script : "./api.js", instances : 4, exec_mode : "cluster" }]}
配置項
-
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 異常重啟情況下,延時重啟時間;
上面內容比較枯燥無味,下面是結合自己實踐中遇到的一些坑做的思考總結。
四,fork與cluster啟動模式
pm2啟動進程的支持兩種模式:fork與cluster,對於了解node的人知道,node的多進程編程api: child_process.fork與cluster。關於pm2的fork與cluster兩者的本質區別,個人認為就是node API的child_process.fork與cluster的區別,stackoverflow有關於這個問題的討論 http://stackoverflow.com/questions/346****35/cluster-and-fork-mode-difference-in-pm2。下面做個粗淺的歸納:
-
cluster是fork的派生,cluster支持所有cluster擁有的特性;
-
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配置項。github上面有作者關於fork模式下是否需要實現cron-like定時的討論:
https://github.com/Unitech/pm2/issues/496
官網文檔注明說,fork模式的定時重啟這個功能不久將實現,期待中吧... ...
五,pm2的監控
pm2的監控有兩種方式:
-
cli方式監控
pm2 monit是專門用來監控的命令,監控項包括cpu與內存
缺點monit展示內容太過粗糙,不夠詳細pm2 list展示當前所有pm2的管理項目
可以查看出每個進程的運行狀態。如果需要更詳細的監控內容,對於cli而言一般都是可以實現的。
這種監控方式的缺點:
a. 不夠直觀,需要自己去執行命令並分析結果;
b. 不便於多台服務器的應用監控管理;
由於這些缺點,就需要一種更好的方式去監控我們的應用
-
keymetrics監控
keymetrics監控是PM2的開發者的開發和維護的一款監控工具,可以嘗試一下,安裝配置非常容易,我也只是粗淺的嘗試了一下,可以參考
http://cnodejs.org/topic/565****00ad12df5d4e050b56
本人對監控研究不多,這里的監控主體是應用進程,非服務器,就只說說我比較喜歡的幾個功能:
a. 利於多服務器監控管理;
b. 代碼異常,可以看出程序長期運行中的穩定性;
c. 支持應用基本的啟動,重啟與停止等功能;
但是,keymetrics是一款商業版的監控軟件,免費版功能有限,且只有兩台服務器的免費配額,這款軟件的服務端非自建,采用的是將應用監控數據定時上拋第三平台,對於有着眾多服務器的公司而言費用昂貴,而且服務器與應用服務進程等狀態信息是敏感性數據,接入到第三方平台中無法接受。當然,如果是服務器數量有限,能夠支付昂貴的使用費用,無敏感數據等場景的話,推薦使用Keymetrics,畢竟是PM2的開發者的開發和維護,功能特性很豐富。
鑒於以上問題,國內牛人開發了一款類似的免費工具,本人沒有研究過,名字很有趣: pm2.5。鏈接地址
http://www.open-open.com/lib/view/open145****0105.html
關於監控,本人經驗不多,就不多妄言了
六,日志問題
日志系統對於任意應用而言,通常都是必不可少的一個輔助功能。pm2的相關文件默認存放於$HOME/.pm2/目錄下,其日志主要有兩類:
a. pm2自身的日志,存放於$HOME/.pm2/pm2.log;
b. pm2所管理的應用的日志,存放於$HOME/.pm2/logs/目錄下,標准誰出日志存放於${APP_NAME}_out.log,標准錯誤日志存放於${APP_NAME}_error.log;
這里之所以把日志單獨說明一下是因為,如果程序開發不嚴謹,為了調試程序,導致應用產生大量標准輸出,使服務器本身記錄大量的日志,導致服務磁盤滿載問題。一般而言,pm2管理的應用本身都有自己日志系統,所以對於這種不必要的輸出內容需禁用日志,重定向到/dev/null。
與crontab比較,也有類似情況,crontab自身日志,與其管理的應用本身的輸出。應用腳本輸出一定需要重定向到/dev/null,因為該輸出內容會以郵件的形式發送給用戶,內容存儲在郵件文件,會產生意向不到的結果,或會導致腳本壓根不被執行;
七,穩定運行建議
PM2是一款非常優秀的Node進程管理工具,它有着豐富的特性:能夠充分利用多核CPU且能夠負載均衡、能夠幫助應用在崩潰后、指定時間(cluster model)和超出最大內存限制等情況下實現自動重啟。
個人幾點看法保證常駐應用進程穩定運行:
1. 定時重啟,應用進程運行時間久了或許總會產生一些意料之外的問題,定時可以規避一些不可測的情況;
2. 最大內存限制,根據觀察設定合理內存限制,保證應用異常運行;
3. 合理min_uptime,min_uptime是應用正常啟動的最小持續運行時長,超出此時間則被判定為異常啟動;
4. 設定異常重啟延時restart_delay,對於異常情況導致應用停止,設定異常重啟延遲可防止應用在不可測情況下不斷重啟的導致重啟次數過多等問題;
5. 設置異常重啟次數,如果應用不斷異常重啟,並超過一定的限制次數,說明此時的環境長時間處於不可控狀態,服務器異常。此時便可停止嘗試,發出錯誤警告通知等。