/ daemon

daemon

守护进程

启动前台任务

node server.js

敲完回车后,我们就不能输入其他命令了,只能等待这个命令运行完了或者手动终止,才能执行其他命令。并且当我们关闭命令行终端后,这个进程就一起退出了。这种任务叫做“前台任务”。

& 启动后台任务

node server.js &

后台任务与前台任务的本质区别:是否继承 stdin。所以,执行后台任务后,我们依然可以接着输入其他命令。

SIGHUP 信号

  1. 用户准备退出 session
  2. 系统向该 session 发出 SIGNUP 信号
  3. session 将 SIGNUP 信号发给所有子进程
  4. 子进程收到 SIGNUP 信号后,自动退出

前台任务会退出就是因为:收到了 SIGHUP 信号。
后台任务是否会退出则由 shell 的参数 huponexit( hup on exit)决定:

pi@raspberrypi ~ $ shopt | grep huponexit

output:

huponexit off

所以说,“后台任务”不会随着 session 一起退出。

disown

如何确保“后台任务”不会因为 huponexiton 而退出呢?

答案是使用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/null
  • 2>&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 + cctrl + d

Tmux

Tmux 比 Screen 功能更多、更强大,它的基本用法如下。

$ tmux
$ node server.js

# 返回原来的session
$ tmux detach

除了tmux detach,另一种方法是按下Ctrl + Bd ,也可以回到原来的 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

Systemd