原理
守護進程(daemon)
守護進程是一類在后臺運行的特殊進程,用于執(zhí)行特定的系統(tǒng)任務(wù)。他獨立于控制終端并且周期性的執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。Linux系統(tǒng)的大多數(shù)服務(wù)器就是通過守護進程實現(xiàn)的。
常見的守護進程包括:
- 系統(tǒng)日志進程syslogd
- Web服務(wù)器httpd
- 郵件服務(wù)器sendmail
- 數(shù)據(jù)庫服務(wù)器mysqld等
守護進程一般在系統(tǒng)啟動時開始運行,除非強行終止,否則會持續(xù)運行知道系統(tǒng)關(guān)機,通常以超級用戶(root)權(quán)限運行。
前臺任務(wù)與后臺任務(wù)
假如有個簡單的go的web服務(wù)器程序,使用如下方式啟動,稱為前臺任務(wù)。獨占了命令窗口,只有運行完了或手動終止(Ctrl+C),才能執(zhí)行其他命令。

如果以如下方式,在命令結(jié)尾加上符號&,啟動的進程就會稱為后臺任務(wù)。

后臺任務(wù)又如下特點:
- 繼承當(dāng)前session的標(biāo)準(zhǔn)輸出(stdout)和標(biāo)準(zhǔn)錯誤(stderr),因此如上圖所示,后臺任務(wù)的所有輸出仍會同步的在命令行顯示
- 不再繼承當(dāng)前session的標(biāo)準(zhǔn)輸入(stdin),無法向這個任務(wù)輸入指令,如果它試圖讀取標(biāo)準(zhǔn)輸入,就會暫停執(zhí)行(halt)
SIGHUP信號
變?yōu)楹笈_任務(wù)并不代表進程成為了守護進程,因為當(dāng)session關(guān)閉后,后臺任務(wù)就會終止。Linux系統(tǒng)終端session退出流程如下:
- 用戶準(zhǔn)備退出session
- 系統(tǒng)向改session發(fā)送
SIGHUP信號 - session將
SIGHUP信號發(fā)送給所有子進程 - 子進程收到
SIGHUP信號后會自動退出
nohup
nohup 是后臺作業(yè)的意思, nohup運行的進程將會忽略終端信號運行。即后臺運行一個命令。nohup COMMAND & 用nohup運行命令可以使命令永久的執(zhí)行下去,和用戶終端沒有關(guān)系,例如我們斷開SSH連接都不會影響它的運行。
使用nohup命令的方式可以啟動一個守護進程,如下圖所示:

nohup命令對進程做了如下操作:
- 忽略
SIGHUP信號,因此當(dāng)session關(guān)閉進程就不會退出 - 關(guān)閉標(biāo)準(zhǔn)輸入,該進程不再接收任何輸入,即使運行在前臺
- 重定向標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯誤到文件nohup.out(默認(rèn)情況,可以指定輸出的文件)
nohup不會自動把進程變?yōu)楹笈_任務(wù),所以必須加上&。
supervisor
supervisor是用Python開發(fā)的一套通用的進程管理程序,能將一個普通的命令行進程變?yōu)楹笈_daemon,并監(jiān)控進程狀態(tài),異常退出時能自動重啟。
supervisor管理進程是通過fork/exec的方式把被管理的進程當(dāng)做子進程來啟動,用戶只需要在配置文件中將要管理的進程進行配置。
結(jié)構(gòu)
supervisor主要由Supervisord、Supervisorctl、Web server和XML-RPC interface組成:
- supervisord:主進程,負(fù)責(zé)管理進程的server,它會根據(jù)配置文件創(chuàng)建指定數(shù)量的應(yīng)用程序的子進程,管理子進程的整個生命周期,對crash的進程重啟,對進程變化發(fā)送事件通知等。同時通過內(nèi)置web server和XML-RPC Interface可以輕松實現(xiàn)進程管理。
- supervisorctl:管理client,用戶通過命令行發(fā)送消息給supervisord,可以查看進程狀態(tài),加載配置文件,啟停進程,查看進程標(biāo)準(zhǔn)輸出和錯誤輸出,遠(yuǎn)程操作等。
- Web server:superviosr提供了web server功能,可通過web控制進程。
- XML-RPC interface: XML-RPC接口,提供XML-RPC服務(wù)來對子進程進行管理和監(jiān)控。
macOS環(huán)境安裝使用
安裝并啟動
$ brew install supervisor
$ brew services start supervisor
創(chuàng)建配置目錄和配置文件
默認(rèn)的配置文件路徑為/usr/local/etc/supervisord.conf,查看該文件可以看到如下內(nèi)容:
$ tail -n2 /usr/local/etc/supervisord.conf
[include]
files = /usr/local/etc/supervisor.d/*.ini
可以看到include了/usr/local/etc/supervisor.d/目錄下的.ini文件,因此我們需要創(chuàng)建改目錄,然后對要管理的進程或進程組創(chuàng)建對應(yīng)的.ini格式的配置文件
$ mkdir -pv /usr/local/etc/supervisor.d
$ vim /usr/local/etc/supervisor.d/myserver.ini
編輯配置文件內(nèi)容如下:
[program:server]
process_name=%(program_name)s_%(process_num)02d
command=/usr/local/go/bin/go run /Users/harryzhang/go/src/server/server.go # 要執(zhí)行的命令
autostart=true # 系統(tǒng)開機自動啟動
autorestart=true # 進程終止自動重啟
user=harryzhang # 用戶
numprocs=1 # 啟動進程數(shù)
redirect_stderr=true # 是否將標(biāo)準(zhǔn)錯誤重定向到標(biāo)準(zhǔn)輸出
stdout_logfile=/Users/harryzhang/go/src/server/server.log # 指定標(biāo)準(zhǔn)輸出保存的文件路徑
重啟supervisor
編輯好配置文件后重啟supervisor就可以生效,可以使用supervisorctl命令查看和管理進程狀態(tài)。
$ brew services restart supervisor
Stopping `supervisor`... (might take a while)
==> Successfully stopped `supervisor` (label: homebrew.mxcl.supervisor)
==> Successfully started `supervisor` (label: homebrew.mxcl.supervisor)
$ supervisorctl status
server:server_00 RUNNING pid 41382, uptime 0:00:04
如果指定的命令執(zhí)行沒有異常,會看到進程已處于運行狀態(tài),如果沒有處于運行狀態(tài),可以查看日志文件,可能為命令執(zhí)行出錯直接退出了。