這兩天在搭建VNC服務的時候,遇到一個簡單的問題,卻困擾了我有一會:網上的教程大部分是修改.service文件,然后啟動服務,但是我發現使用vncserver這個命令也可以達到同樣的目的,這兩者之間有什么區別呢?查了一些資料,簡單的做一個總結。
工作管理
一般情況下,我們可能會在命令行下這樣啟動一個程序,以新做的版本管理系統為例:
java -jar VersionManager.jar
現在,內網中的其他機器可以通過80端口訪問本機提供的web服務了。一切都很正常。
注意到一個問題,新啟動的程序獨占了命令行窗口,并隨時打印一些程序運行期間的log出來。
如果想在同一個命令行窗口再執行其他命令,那么需要Ctrl+c停止這個web服務才可以。
這個時候的web服務稱為前臺任務
,一旦我們退出這個命令行窗口,該服務也隨之關閉,無法訪問。
如何將其變成一個后臺執行的任務,從而不影響命令行再執行其他命令呢?
java -jar VersionManager.jar &
只要在命令的尾部加上符號&,啟動的進程就會成為"后臺任務"。"后臺任務"有兩個特點:
繼承當前 session (對話)的標準輸出(stdout)和標準錯誤(stderr)。因此,后臺任務的所有輸出依然會同步地在命令行下顯示。
不再繼承當前 session 的標準輸入(stdin)。你無法向這個任務輸入指令了。如果它試圖讀取標準輸入,就會暫停執行(halt)。
所以,我們以上述方式啟動web服務,他的運行日志依然會打印在屏幕上面。但是與前臺任務的一個區別就是,現在可以在命令行執行其他命令了,所有的輸出都會混雜在一起打印在屏幕上。
有沒有辦法解決這種問題呢?那就是重定向:
java -jar VersionManager.jar >info.log 2>&1 &
上述命令把web服務輸出的標準輸出和標準錯誤信息都重定向到了info.log這個文件,屏幕上不會再有任何的信息被打印出來了。你也可以像之前那樣查看web服務的輸出信息:
tail -f info.log
此時,web服務的輸出又動態的在屏幕上打印出來了。
如果要讓正在運行的"前臺任務"變為"后臺任務",可以先按ctrl + z,然后執行bg命令。(讓最近一個暫停的"后臺任務"繼續執行)
如何查看當前session有哪些后臺任務在運行呢?
$ jobs -l //打印pid
[1]- 17000 運行中 nohup java -jar VersionManager.jar > logs/info.log 2>&1 &
[2]+ 22738 停止 vim cron.log
將指定的后臺任務變成前臺執行:
fg 2 //繼續編輯cron.log
最后做一個小結:
查看后臺任務:jobs -l
將后臺任務取回前臺:fg number //number為任務號
暫停前臺任務,并將任務放到后臺:ctrl + z
暫停的后臺任務繼續執行:bg number //number為任務號
結束前臺任務:ctrl + c
結束后臺任務:kill pid //pid可以通過jobs -l進行查看
脫機管理
通過上面的內容,我們了解到如何將一個任務放在后臺執行。后臺任務都是基于當前session的,如果我們退出了當前的session(關閉了命令行窗口或執行exit),后臺任務還會執行嗎?
想起了之前有個現場的技術支持人員打電話跟我反映,一個rest服務總是無規律的宕掉。剛開始我也想不通,后來才想到是上面提到的原因...
看一下session退出的時候發生了什么:
用戶準備退出 session
系統向該 session 發出SIGHUP信號
session 將SIGHUP信號發給所有子進程
子進程收到SIGHUP信號后,自動退出
上面的流程可以解釋,隨著session退出,前臺任務也會結束。那么后臺任務是否也會收到SIGHUP信號后退出呢?
這由 Shell 的huponexit參數決定的。
shopt | grep huponexit
執行上面的命令,就會看到huponexit參數的值。如果顯示off
,表示session 退出的時候,不會把SIGHUP信號發給"后臺任務",從而"后臺任務"不會隨著 session 一起退出。
但是,為了確保我們的web服務變成一個可靠的守護進程,我們應該顯式的指出 session 退出的時候,不把SIGHUP信號發給"后臺任務":
nohup
nohup java -jar VersionManager.jar &
nohup
對java -jar VersionManager.jar
命令做了幾件事:
阻止SIGHUP信號發到這個進程。
關閉標準輸入。該進程不再能夠接收任何輸入,即使運行在前臺。
重定向標準輸出和標準錯誤到文件nohup.out。
一般情況下,我們會重定向web服務的輸出:
nohup java -jar VersionManager.jar >info.log 2>&1 &
至此,我們的web服務已經變成了一個可靠的守護進程。
tmux
還有一種方法,那就是使用tmux。tmux可以在當前session里新建一個session。當前的session退出不會影響到新建的session。重新登錄之后還可以連上之前建立的session。
// 新建 session
$ tmux new -s session_name
// 切換到指定 session
$ tmux attach -t session_name
// 列出所有 session
$ tmux list-sessions
// 退出當前 session,返回前一個 session
$ tmux detach
// 殺死指定 session
$ tmux kill-session -t session-name
systemd服務
systemd 是 Linux 下的一款系統和服務管理器。Systemd 并不是一個命令,而是一組命令,涉及到系統管理的方方面面。
在centos7中,我們也許會使用systemd來管理我們的一些程序,比如ssh:
// 啟動ssh服務
systemctl start sshd.service
// 設置ssh服務開機啟動
systemctl enable sshd.service
...
我們也可以通過systemd來管理我們的守護進程,成為真正意義上的系統服務。
關于systemd的使用不再贅述,參考Systemd (簡體中文)