在 Linux 服务器上跑程序,最烦的就是终端一关程序就停了。这篇记录一下常用的几种后台运行方案,从最简单的 nohup 到生产环境用的 Supervisor。
问题场景分析
为什么终端关闭会终止程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ┌─────────────────────────────────────────────────────────────┐ │ 终端关闭导致进程终止的原理 │ ├─────────────────────────────────────────────────────────────┤ │ │ 登录终端 │ │ │ ▼ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ bash │────►│ 子进程 │────►│ 程序 │ │ │ (shell)│ │ (sh/php)│ │(node) │ │ └────┬────┘ └─────────┘ └────┬────┘ │ │ │ │ │ SIGHUP 信号 │ │ │ 终端挂起时发送 │ │ ▼ ▼ │ 用户关闭终端 ──────────────────────► 子进程收到 SIGHUP │ │ │ │ │ │ 默认行为:终止进程 │ │ ▼ │ └────────────────────────────► 程序退出 │ │ 解决方案:让程序忽略 SIGHUP 信号 │
|
当终端(TTY)关闭时,操作系统会向该终端下运行的所有进程发送 SIGHUP(挂起信号,Signal Hang Up)。默认情况下,进程收到此信号后会终止执行。
方案一:nohup 命令
基本用法
nohup(no hang up)是最简单、最常用的后台运行方案,它会让程序忽略 SIGHUP 信号。
1 2 3 4 5 6 7 8 9 10 11
| nohup ./your_program &
nohup node server.js &
nohup python3 script.py &
nohup ./your_program > output.log 2>&1 &
|
输出重定向详解
| 命令 |
作用 |
nohup command & |
标准输出重定向到 nohup.out |
nohup command > app.log & |
输出到 app.log,错误丢弃 |
nohup command > app.log 2>&1 & |
标准输出和错误都写入 app.log |
nohup command > /dev/null 2>&1 & |
完全丢弃所有输出 |
常用操作
1 2 3 4 5 6 7 8
| ps aux | grep node
kill -9 PID
tail -f nohup.out
|
优缺点
| 优点 |
缺点 |
| 使用简单,无需额外安装 |
程序崩溃后不会自动重启 |
| 几乎所有 Linux 系统自带 |
无进程监控功能 |
| 适合临时运行任务 |
重启服务器后需手动重新启动 |
方案二:disown 与作业控制
disown 命令
如果已经在终端启动了程序但忘记使用 nohup,可以使用 disown 将作业从 shell 的作业表中移除,使其不受 SIGHUP 影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ./long_running_task &
jobs -l
disown
disown %1
disown -a
|
setsid 命令
setsid 会创建一个新的会话(session),使进程成为新会话的领头进程,从而完全脱离当前终端。
1 2 3 4 5
| setsid ./your_program
|
三种方案对比
| 方案 |
脱离终端 |
自动重启 |
使用场景 |
nohup |
是 |
否 |
简单后台任务 |
disown |
是 |
否 |
已启动程序的补救 |
setsid |
是(完全) |
否 |
需要完全脱离终端 |
方案三:screen / tmux 终端复用
screen 工具
screen 是一个终端复用器,可以在一个物理终端上创建多个虚拟终端,即使网络断开,会话中的程序也会继续运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| sudo apt-get install screen sudo yum install screen
creen -S mysession
node server.js
screen -ls
screen -r mysession
screen -rD mysession
|
tmux 工具(推荐)
tmux 是 screen 的现代化替代品,功能更强大,界面更友好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| sudo apt-get install tmux
tmux new -s myapp
tmux ls
tmux attach -t myapp
tmux kill-session -t myapp
|
screen vs tmux
| 特性 |
screen |
tmux |
| 默认快捷键 |
Ctrl+A |
Ctrl+B |
| 窗口分割 |
较弱 |
强大 |
| 配置灵活性 |
一般 |
高(支持主题、插件) |
| 脚本化 |
支持 |
更完善 |
| 社区活跃度 |
稳定 |
活跃 |
方案四:Supervisor 进程管理
什么是 Supervisor
Supervisor 是一个用 Python 编写的客户端/服务器系统,用于控制和监控类 Unix 操作系统上的进程。它是生产环境中最常用的进程管理工具之一。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| ┌─────────────────────────────────────────────────────────────┐ │ Supervisor 架构 │ ├─────────────────────────────────────────────────────────────┤ │ │ ┌──────────────┐ ┌──────────────┐ │ │ supervisord │◄────────│ supervisorctl│ │ │ (服务端) │ Unix │ (客户端) │ │ │ │ Socket │ │ │ └──────┬───────┘ └──────────────┘ │ │ │ │ 监控和管理 │ ▼ │ ┌──────────────────────────────────────────────────────┐ │ │ 被管理的进程组 │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ Node.js│ │ Python │ │ Redis │ │ Nginx │ │ │ │ │ Server │ │ Worker │ │ Server │ │ Proxy │ │ │ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │ └──────────────────────────────────────────────────────┘ │ │ 核心功能: │ • 自动启动进程 │ • 进程崩溃自动重启 │ • 日志轮转 │ • 进程组管理 │ • Web 界面监控(可选) │
|
安装 Supervisor
1 2 3 4 5 6 7 8 9
| sudo apt-get install supervisor
sudo yum install supervisor
sudo systemctl start supervisor sudo systemctl enable supervisor
|
配置文件
Supervisor 的主配置文件位于 /etc/supervisor/supervisord.conf(Debian/Ubuntu)或 /etc/supervisord.conf(CentOS)。
在 /etc/supervisor/conf.d/ 目录下创建应用配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| [program:node-app]
command=/usr/bin/node /var/www/app/server.js
directory=/var/www/app
autostart=true
autorestart=true
startretries=3
startsecs=5
user=www-data
environment=NODE_ENV="production",PORT="3000"
stdout_logfile=/var/log/supervisor/node-app.log stdout_logfile_maxbytes=10MB stdout_logfile_backups=5 stderr_logfile=/var/log/supervisor/node-app-error.log stderr_logfile_maxbytes=10MB stderr_logfile_backups=5
numprocs=1
process_name=%(program_name)s
|
常用管理命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| sudo supervisorctl reread sudo supervisorctl update
sudo supervisorctl start node-app sudo supervisorctl stop node-app sudo supervisorctl restart node-app
sudo supervisorctl status
sudo supervisorctl tail -f node-app
sudo supervisorctl stop all
|
进程组配置
当有多个相关联的进程需要一起管理时,可以使用进程组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| [program:myproject-worker] command=/usr/bin/python3 /var/www/project/worker.py autostart=true autorestart=true user=www-data stdout_logfile=/var/log/supervisor/worker.log
[program:myproject-scheduler] command=/usr/bin/python3 /var/www/project/scheduler.py autostart=true autorestart=true user=www-data stdout_logfile=/var/log/supervisor/scheduler.log
[group:myproject] programs=myproject-worker,myproject-scheduler priority=999
|
管理进程组:
1 2
| sudo supervisorctl restart myproject:*
|
方案五:systemd 服务管理
创建 systemd 服务
对于现代 Linux 发行版(CentOS 7+、Ubuntu 16.04+、Debian 8+),systemd 是系统和服务管理器,也是配置后台服务的标准方式。
创建服务文件 /etc/systemd/system/myapp.service:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| [Unit] Description=My Node.js Application After=network.target
[Service] Type=simple User=www-data WorkingDirectory=/var/www/app ExecStart=/usr/bin/node server.js Restart=always RestartSec=10 Environment=NODE_ENV=production PORT=3000
StandardOutput=syslog StandardError=syslog SyslogIdentifier=myapp
[Install] WantedBy=multi-user.target
|
管理服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl stop myapp
sudo systemctl restart myapp
sudo systemctl status myapp
sudo systemctl enable myapp
sudo systemctl disable myapp
sudo journalctl -u myapp -f
|
systemd vs Supervisor
| 特性 |
systemd |
Supervisor |
| 系统集成度 |
高(系统级) |
中(应用级) |
| 配置复杂度 |
较复杂 |
简单 |
| 日志管理 |
journalctl |
内置轮转 |
| Web 界面 |
无 |
有(需配置) |
| 适用场景 |
系统服务 |
应用进程 |
| 跨发行版一致性 |
现代系统通用 |
完全一致 |
方案选择决策树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| ┌─────────────────────────────────────────────────────────────┐ │ Linux 后台运行方案选择指南 │ ├─────────────────────────────────────────────────────────────┤ │ │ 是临时运行还是长期服务? │ │ 临时 ────────► nohup / screen / tmux │ │ │ 长期 │ │ │ ▼ │ 需要自动重启吗? │ │ 不需要 ──────► nohup + cron 检查 │ │ │ 需要 │ │ │ ▼ │ 单应用还是多进程管理? │ │ 单应用 ──────► systemd(现代系统) │ │ Supervisor(跨平台兼容) │ │ │ 多进程 ──────► Supervisor(推荐) │ PM2(Node.js 专用) │
|
最佳实践建议
1. 日志管理
无论使用哪种方案,都应确保日志不会无限增长:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| cat > /etc/logrotate.d/myapp << 'EOF' /var/log/myapp/*.log { daily rotate 14 compress delaycompress missingok notifempty create 0644 www-data www-data sharedscripts postrotate /usr/bin/supervisorctl restart myapp > /dev/null 2>&1 endscript } EOF
|
2. 健康检查
在程序中实现健康检查端点,配合外部监控:
1 2
| * * * * * /usr/bin/curl -f http://localhost:3000/health || /usr/bin/systemctl restart myapp
|
3. 环境变量管理
避免在配置文件中硬编码敏感信息:
1 2 3
| [Service]
EnvironmentFile=/etc/myapp/environment
|
1 2 3
| DATABASE_URL=postgres://user:pass@localhost/db SECRET_KEY=your-secret-key
|
写在最后
Linux 进程守护方案对比:
| 方案 |
复杂度 |
可靠性 |
监控能力 |
推荐场景 |
nohup |
低 |
中 |
无 |
临时任务、开发测试 |
screen/tmux |
低 |
中 |
无 |
交互式会话、手动操作 |
Supervisor |
中 |
高 |
强 |
生产环境应用进程 |
systemd |
中 |
高 |
中 |
系统服务、现代 Linux |
对于生产环境,推荐使用 Supervisor 或 systemd 进行进程管理,它们提供了自动重启、日志轮转、进程组管理等核心功能,确保服务的高可用性。