daemon
守护进程
启动前台任务
node server.js
敲完回车后,我们就不能输入其他命令了,只能等待这个命令运行完了或者手动终止,才能执行其他命令。并且当我们关闭命令行终端后,这个进程就一起退出了。这种任务叫做“前台任务”。
& 启动后台任务
node server.js &
后台任务与前台任务的本质区别:是否继承 stdin。所以,执行后台任务后,我们依然可以接着输入其他命令。
SIGHUP 信号
- 用户准备退出 session
- 系统向该 session 发出 SIGNUP 信号
- session 将 SIGNUP 信号发给所有子进程
- 子进程收到 SIGNUP 信号后,自动退出
前台任务会退出就是因为:收到了 SIGHUP 信号。
后台任务是否会退出则由 shell 的参数 huponexit
( hup on exit)决定:
pi@raspberrypi ~ $ shopt | grep huponexit
output:
huponexit off
所以说,“后台任务”不会随着 session 一起退出。
disown
如何确保“后台任务”不会因为 huponexit
为 on
而退出呢?
答案是使用disown
将特定的“后台任务”从“后台任务”列表(jobs
命令的返回结果)中移除。原因是 session 会向“后台”列表发送 SIGHUP
信号。
node server.js &
disown
# 移出最近一个正在执行的后台任务
$ disown
# 移出所有正在执行的后台任务
$ disown -r
# 移出所有后台任务
$ disown -a
# 不移出后台任务,但是让它们不会收到SIGHUP信号
$ disown -h
# 根据jobId,移出指定的后台任务
$ disown %2
$ disown -h %2
标准 I/O
- 0 输入(标准输入)
- 1 输出(标准输出)
- 2 错误(标准错误信息输出)
使用 disown
命令之后,还有一个问题。那就是,退出 session 后,如果后台进程与 标准I/O 有交互,它还是会挂掉。这是因为"后台任务"的标准 I/O 继承自当前 session,disown命令并没有改变这一点。一旦"后台任务"读写标准 I/O,就会发现它已经不存在了,所以就报错终止执行。为了解决这个问题,需要对"后台任务"的标准 I/O 进行重定向。
node server.js > stdout.txt 2> stderr.txt < /dev/null &
disown
nohup 忽略所有挂断(SIGHUP)信号
nohup 比 disown 更方便。
nohup node server.js &
nohup 命令对 server.js 进程做了三件事:
- 阻止 SIGHUP 信号发送到这个进程。
- 关闭标准输入。该进程不再接受任何输入,即使运行在前台。
- 重定向 标准输入 和 标准错误 到文件 nohup.out
也就是说,nohup 命令将子进程与它所在的 session 分离了。
注意: nohup 命令不会自动把进程变为“后台任务”,所以必须加上 & 符号。
nohup command > log.file 2>&1 &
> /dev/null
means: stdout goes to /dev/null2>&1
means: stderr also goes to the stdout
# 1. 先编辑一支会『睡著 500 秒』的程序:
[root@www ~]# vim sleep500.sh
#!/bin/bash
/bin/sleep 500s
/bin/echo "I have slept 500 seconds."
# 2. 丢到后台中去运行,并且立刻注销系统:
[root@www ~]# chmod a+x sleep500.sh
[root@www ~]# nohup ./sleep500.sh &
[1] 5074
[root@www ~]# nohup: appending output to ‘nohup.out’ <==会告知这个信息!
[root@www ~]# exit
如果你再次登陆的话,再使用 pstree 去查阅你的程序,会发现 sleep500.sh 还在运行中喔!
pstree
pstree
ps -ef | grep sleep500
# pid 为 14807
# 15 正常终止
sudo kill -15 14807
# 9 强制终止
sudo kill -9 14807
Screen 命令与 Tmux 命令
另一种思路是:在当前 session 里面,新建另一个 session。这样的话,当前 session 一旦结束,不影响其他 session。而且,以后重新登录,还可以再连上早先新建的 session。
Screen
Screen 的用法如下。
# 新建一个 session
$ screen
$ node server.js
然后,按下ctrl + A和ctrl + D,回到原来的 session,从那里退出登录。下次登录时,再切回去。
$ screen -r
如果新建多个后台 session,就需要为它们指定名字。
$ screen -S name
# 切回指定 session
$ screen -r name
$ screen -r pid_number
# 列出所有 session
$ screen -ls
如果要停掉某个 session,可以先切回它,然后按下ctrl + c
和ctrl + d
。
Tmux
Tmux 比 Screen 功能更多、更强大,它的基本用法如下。
$ tmux
$ node server.js
# 返回原来的session
$ tmux detach
除了tmux detach,另一种方法是按下Ctrl + B
和d
,也可以回到原来的 session。
# 下次登录时,返回后台正在运行服务session
$ tmux attach
如果新建多个 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
Node 工具
- forever,功能很简单,就是保证进程退出时,应用会自动重启。
- nodemon,一般只在开发时使用,它最大的长处在于 watch 功能,一旦文件发生变化,就自动重启进程
- pm2,功能最强大,除了重启进程以外,还能实时收集日志和监控。
npm install -g forever
# 作为前台任务启动
$ forever server.js
# 作为服务进程启动
$ forever start app.js
# 停止服务进程
$ forever stop Id
# 重启服务进程
$ forever restart Id
# 监视当前目录的文件变动,一有变动就重启
$ forever -w server.js
# -m 参数指定最多重启次数
$ forever -m 5 server.js
# 列出所有进程
$ forever list
# 默认监视当前目录的文件变化
$ nodemon server.js
# 监视指定文件的变化
$ nodemon --watch app --watch libs server.js
npm install -g pm2
# 启动应用
$ pm2 start app.js
# 指定同时起多少个进程(由CPU核心数决定),组成一个集群
$ pm2 start app.js -i max
# 列出所有任务
$ pm2 list
# 停止指定任务
$ pm2 stop 0
# 重启指定任务
$ pm2 restart 0
# 删除指定任务
$ pm2 delete 0
# 保存当前的所有任务,以后可以恢复
$ pm2 save
# 列出每个进程的统计数据
$ pm2 monit
# 查看所有日志
$ pm2 logs
# 导出数据
$ pm2 dump
# 重启所有进程
$ pm2 kill
$ pm2 resurect
# 启动web界面 http://localhost:9615
$ pm2 web