上一篇把程序跑起来了,但好日子没几天。第一天你 ssh 进去想看一眼,结果什么都没有,程序不知道什么时候挂了。第二天终于跑住了,你一关终端窗口,它又没了。服务器上的程序活得像个需要人盯着的孩子,问题就出在你对「进程、日志、端口、终端」这几件事没有完整的认识。这篇把排查和保活一起讲透,学完你的程序才真正算「部署完成」。
问题来了,先搞清楚程序还活着没
判断程序生死,靠的是 ps 这个查看进程的命令。aux 三个字母的组合表示显示所有进程的完整信息,
bash
ps aux | grep python
grep python 是从输出里筛选关键词。看到一行包含你程序名的记录,说明它还活着,第二列的数字是它的进程号(PID),后面排查和杀进程都要用到。什么都没有,说明已经退出了。
还有一种「活着但没反应」的状态,程序进程在,但服务没响应。这种时候就不该再看进程了,往下走,看日志和端口。
病根基本都在日志里
程序把运行情况写进日志文件,这是排查的第一现场。实时跟踪日志输出,
bash
tail -f 你的日志文件路径
-f 表示持续跟踪,新写入的内容会实时滚出来。看完按 Ctrl+C 退出跟踪。
按惯例讲,日志不是垃圾信息,崩溃前最后几行往往直接写着原因。最常见的两种,没找到文件,路径配置错;连不上外部服务,数据库或 API 的地址、端口不对。大多数程序挂掉,根因就藏在这几行里。
顺带提一句,服务器的资源情况也值得瞄一眼,
bash
free -h # 看内存
df -h # 看磁盘
程序突然「不知道为什么崩了」,很多时候是内存被吃满或者磁盘写满了。你想想看,程序一崩就去看代码,但资源和日志往往先于代码暴露真相。这两个命令的输出是即时的,内存看 free -h 的 available 列,磁盘看 df -h 的 Use% 列,超过 90% 就该动手清理了。先看资源再看代码,很多玄学问题当场就破了案。
端口被占,web 服务的老事故
如果你的程序要对外提供服务,会监听一个端口。端口被占用是 web 类应用的经典事故,比如你昨天部署的另一个服务还占着 8000,新程序自然起不来,报错可能是「Address already in use」也可能是别的,反正看日志不一定能一眼看出来。
查看本机端口监听情况,
bash
ss -tlnp
ss 是查看网络连接的命令,-t 只看 TCP,-l 只看监听中的,-n 显示数字端口,-p 显示占用进程。看到目标端口后面跟着别的程序名,就是它把路堵了。
三件套到此就齐了,ps 看进程、tail 看日志、ss 看端口。它们针对的是三类不同的问题,进程不在了是程序崩溃,进程在但服务没反应是内部错误或资源耗尽,端口被占是新起的服务起不来。记住了这个对应关系,排查就不会像无头苍蝇。
排查铁律,先确认问题类型,再选对应工具。进程、日志、端口,三类问题三件工具,别用错方向。
杀掉僵住的进程
程序僵住了,比如卡在死循环里,这时候的诉求从「查」变成「杀」。还是用前面学的,找到进程号再动手,
bash
ps aux | grep 你的程序
kill 进程号 # 正常终止
kill -9 进程号 # 强制杀掉,最后手段
kill 默认发温和的终止信号,给了程序善后时间。-9 是强制击杀,用于前面那招无效的情况。注意别把 PID 搞错,杀错进程是新手最容易犯的事故。
让程序脱离你的终端
回到开头那个问题,程序明明起来了,一关 SSH 窗口就消失。原因是终端关闭时,系统会给这个终端下的所有进程发一个挂断信号(SIGHUP),进程收到信号就默认退出了。
逃出这个限制有两个手段,
bash
python main.py & # 后台运行
nohup python main.py & # 后台运行 + 忽略挂断信号
& 把进程丢到后台,nohup 让进程无视终端的关闭信号。配合日志重定向,程序就彻底脱离了你的终端,
bash
nohup python main.py > app.log 2>&1 &
这条命令的每一个零件都值得记住,> 是输出重定向,2>&1 表示把报错也一并写进日志,末尾的 & 是后台运行。之后不管终端怎么关,程序照跑,日志都进 app.log。
但 nohup 有个短板,它只管「不死」,不管「想不想让它休」。程序占着前台,你想再进服务器做点别的事都难,更别说回头再看一眼程序界面。想要重新看到程序舍不得放的输出,得靠 tmux。
tmux,把整个终端会话托管起来
tmux(terminal multiplexer,终端复用器)是跑在服务器上的一个守护进程,它把你打开的终端窗口托管起来,即使 SSH 连接断开,窗口和里面跑的程序依旧留在服务器上。
区别在哪,nohup 是「让程序活下来」,tmux 是「让整个终端会话活下来」。其实这俩不冲突,只是解决两个不同层面的问题。前者你只能靠日志确认程序状态,后者你可以随时再连回去,重新看到那个界面,继续跟程序交互。
终端会话与进程存活是两件事,tmux 管的是前者,nohup 管的是后者。
Ubuntu 20.04 之后基本都自带 tmux,没有就一条命令安装,
bash
sudo apt install -y tmux
tmux 的日常操作只有三个,新建会话、离开会话、回到会话。
bash
tmux new -s myapp
python main.py
-s myapp 是给会话起名,之后按名字找它。程序开始在会话里跑起来后,按 Ctrl+B 再按 D,脱离会话。这是 tmux 的核心操作,先按组合键,松开,再按 D,不要一起按。
此时你又回到了普通 SSH 命令行,但程序还在那个会话里继续跑。下次登录服务器,随时回到会话,
bash
tmux attach -t myapp
程序的原界面立刻出现在你眼前,就跟从未离开过一样。不再需要了,先 attach 进去退出程序,或直接删会话,
bash
tmux kill-session -t myapp
会话活着的时候,里面还有几个高频操作值得记下。
| 快捷键 | 作用 |
|---|---|
| Ctrl+B 然后 D | 脱离会话,程序继续跑 |
| Ctrl+B 然后 C | 在会话里开一个新终端窗口 |
| Ctrl+B 然后 N | 切换到下一个窗口 |
| Ctrl+B 然后 0-9 | 直接跳到对应编号的窗口 |
打开多个窗口这个能力很实用。一个窗口跑程序盯日志,另一个窗口继续敲命令操作服务器,互不干扰,这是纯 nohup 方案给不了的自由度。
坦率讲,tmux 适合「手工挂机」场景,但有一类需求它管不了。服务器重启、程序崩溃自动拉起、开机自启,这些 tmux 都做不到,那是 systemd 的领域。
| 维度 | tmux | systemd |
|---|---|---|
| 本质 | 终端会话托管 | 系统服务管理 |
| 适配场景 | 手动挂机、开发调试 | 生产服务、开机自启 |
| 崩溃自动重启 | 不行 | 可以 |
| 学习成本 | 低,一篇学会 | 较高,要写配置 |
判断标准很简单,自己手动跑着玩的工具用 tmux。要 7x24 对外提供服务、机器重启后要自动恢复的,去学 systemd 服务文件。
生产级的路还有多远
两篇的路走到这里收个尾。回头看全套流程,买的是一台永远在线的电脑,进出靠 SSH,文件靠 tar 和 scp,环境靠 venv 和镜像源,出问题靠 ps、tail、ss 三件套,保活靠 nohup 和 tmux。每一步解决的其实都是同一件事,让程序离开你的电脑也能可靠运行。
- 进程不在了查 ps,服务没反应查 tail,端口被占查 ss,先分型再动手
- free 和 df 瞄一眼资源,很多玄学崩溃当场破案
- nohup 让进程活,tmux 让会话活,两者搭配各司其职
- tmux 三连,new 建会话、attach 回会话、kill 删会话,Ctrl+B 是总开关
- 要崩溃自动拉起、开机自启,从 systemd 入门开始
再往下进阶的方向也给你列好。域名解析与 Nginx 反向代理,让服务有名字、走 80/443 端口;crontab 定时任务,让服务器到点自动干活;systemd 服务化,把生产级保活讲透。服务器这扇门已经推开了,剩下的路走得越深越好玩。