如何优雅地运行一个 Daemon
Daemon 是运行在后台的进程,俗称守护进程,常见的 apache, nginx 和 mysql 等都是以守护进程的形式运行。本文主要介绍其的原理以及如何优雅地运行一个 daemon。
The theory
Advanced Programming in the Unix Environmen 第三版本的 13 章详细的介绍了 daemon 的原理、特征和编程规则。它通常具有以下特点:
- 父进程多数为 1,父进程为 0 的进程通常是内核进程
- 无控制终端,即不受终端的控制
- 多数以超级用户特权运行
创建 daemon 的过程如下:
- 设置 umask 为 0,避免因父进程权限小而引起权限相关问题
- 调用 fork 创建子进程,之后父进程退出,子进程继续运行
- 调用 setsid 创建新会话并成为新进程组组长和新会话首进程,同时失去控制终端
- 把工作目录改为根目录
- 关闭不需要的文件描述符
- 把标准输出和错误重定向到 /dev/null,并且以 /dev/null 作为标准输入,隔绝与终端的交互。
The simple way
以下是一种运行 daemon 简单的方法:
nohup COMMAND >/dev/null 2>&1 &
>/dev/null 2>&1
先介绍 Linux shell 的一些基本概念,如文件描述符和重定向:
- 0: 标准输入的文件描述符
- 1: 标准输出的文件描述符,如果没有明确指出,那么通常 1 为默认值,即标准输出
- 2: 标准错误输出的文件描述符
- >: 重定向符
- /dev/null: 空设备文件,它丢弃一切写入其中的数据,但会报告写入成功
所以 >/dev/null 2>&1 的含义如下:
- >/dev/null 因没有明确指出文件描述符,所以默认为标准输出,即把标准输出重定向到 /dev/null
- 2>&1,标准错误重定向到标准输入,因标准输出被重定向到 /dev/null,所以标准错误最终也会被重定向到 /dev/null
+---------+ +------------+ > +-----------+
| | ---------------- | standout 1 | ----> | /dev/null |
| | +---> +------------+ +-----------+
| Program | | >
| | |
| | +------------+
| | ---- | standerr 2 |
+---------+ +------------+
以下是一些功能等价的命令,都是把标准输出和标准错误重定向到 /dev/null 中,更多的细节请参考 Adanced Bash-Scripting Guide。
- >/dev/null 2>/dev/null
- &>/dev/null
- >/dev/null 2>&-
&
如果某个 Command 以 & 结尾,shell 会在后台执行该命令并且立马返回,不需要等到命令执行完。
nohup
忽略 SIGHUP 信号,避免因父 shell 退出而导致 COMMAND 启动的子进程被杀死。
The better way
优秀从模仿开始,欲知如何优雅的运行一个 daemon,我们应该分析 linux 的做法,linux 环境下通常用 service 启动各种 daemon:
service apache start
service sshd start
service nginx start
......
Service 最终调用 /etc/inti.d/ 目录下的脚本启动相应的服务,这些脚本就是我们的学习样本,以 nginx 为例,精简版的脚本如下:
. /lib/lsb/init-functions
case "$1" in
start)
start-stop-daemon --start --quiet --pidfile /run/nignx.pid --exec /usr/sbin/nginx 2>/dev/null
;;
stop)
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /run/nignx.pid --name nginx
;;
esac
exit 0
和上节的方法相比,通过 service 命令具有以下优点:
- 操作简洁,友好规范
- 完整的生命周期管理,支持 start/stop/restart/status 操作
- 可在脚本中做前置工作检查、后置清理等
另一件很有趣的事情就是绝大多数 /etc/init.d 下的守护进程都是以 start-stop-daemon 命令启动,和 nohup 相比,它的功能更为丰富,支持启动和杀死 daemon,支持后台运行,支持以某个用户的身份运行等等,更多信息请见 man start-stop-daemon。