🐧 第04章 · 服务与进程管理

systemctl ps kill

服务与进程管理

服务器上跑着的一堆东西,要么是受 systemd 托管的"服务",要么是临时发作的"进程"。这一章讲清 Systemd 服务管理(systemctl)与进程管理(ps/kill)两套工具,以及本机 Node 应用、Nginx、MySQL 的日常管理。

进程 vs 服务

  • 进程 (Process) —— 一个运行中的程序,有 PID,是 ps/kill 管理的对象;
  • 服务 (Service) —— 受 systemd 托管的常驻进程,有 unit 名,是 systemctl 管理的对象。

两者关系:一个服务往往就是一个进程(或多进程)。本机 bangdream.service 底层就是那个 Node 进程。

服务管理:systemctl

Systemd 是 Ubuntu 24.04 的 init 系统,PID 1。systemctl 是最常用命令:

命令 作用 示例
systemctl status <u> 查看状态与最近日志 systemctl status nginx
systemctl start <u> 启动 systemctl start nginx
systemctl stop <u> 停止 systemctl stop nginx
systemctl restart <u> 重启 systemctl restart bangdream
systemctl reload <u> 重载配置(不中断连接) systemctl reload nginx
systemctl enable <u> 开机自启 systemctl enable nginx
systemctl disable <u> 取消开机自启 systemctl disable nginx
systemctl is-active <u> / is-enabled <u> 立即显示 active/enabled systemctl is-active mysql
systemctl status bangdream       # 看状态+最近几行日志,最常用
systemctl restart lovelive       # 重启 Node 服务
systemctl enable --now nginx     # 开机自启并立即启动(-now 一步到位)
systemctl list-units --type=service --state=running | head   # 列出正在运行的服务

易错 修改了 unit 文件(/etc/systemd/system/xxx.service)后必须 systemctl daemon-reload 重载,否则新配置不生效,很多人改完发现没效果就是漏了这一步。

开机自启管理

服务是"现在启动"还是"开机启动",是两个独立状态,用 is-active/is-enabled 分别看:

systemctl is-enabled nginx       # enabled / disabled / static
systemctl is-active  nginx       # active / inactive
systemctl list-unit-files | grep -E "nginx|mysql|bangdream"   # 列出含这些字的 unit 及自启状态
systemctl mask bash.service      # 彻底禁用一个服务(rename 到 /dev/null,比 disable 更硬)

易错 enable 只设置开机自启,不会立即启动;要既自启又立刻跑,用 enable --now。mask 和 disable 不同:mask 会把 unit 链接到 /dev/null,任何人调 start/restart 都无效,适合"永久禁掉易冲突的服务"。

服务的配置文件在哪

  • 系统自带:/lib/systemd/system/(apt 装的);
  • 管理员自建:/etc/systemd/system/(你或程序装的);
  • 查看:systemctl cat <u>。
systemctl cat bangdream        # 一键看 unit 文件位置与内容

本机 Node 服务的 unit 大概形如:

[Service]
ExecStart=/usr/local/bin/node server.js
WorkingDirectory=/var/www/bangdream
Restart=on-failure

Restart=on-failure 说明进程崩溃会自动拉起,这是生产服务的标配——这也是 Node 应用崩溃后"自己又活了"的原因。

进程查看:ps 与 top

ps 是静态快照:

ps aux                # 列出所有进程(BSD 风格,-aux 三参数)
ps -ef                # 列出所有进程(System V 风格,-e -f)
ps aux | grep nginx    # 过滤出含 nginx 的行
# 按 PID 找进程,或反转
ps -p $(pgrep nginx) -o pid,cmd    # pgrep 找 PID 再取详情
pgrep -af node                       # 列出所有 node 进程及其完整命令行
pidof node                          # 输出 node 的 PID(可能多个)

top 是实时视图,前面已介绍;htop 是它的彩色增强版(需安装):

htop                  # 彩色进程列表,可 F5 看进程树,F9 kill

结束进程:kill 与信号

进程间用"信号"通信,kill 发送信号:

信号 编号 含义 适度
TERM 15 请求优雅退出 常规推荐,先给进程自我清理的机会
KILL 9 强制杀死 兜底,进程无法清理就立即消失
HUP 1 重载配置/日志 部分服务用它 reload
kill <pid>              # 默认 15,优雅结束
kill -9 <pid>           # 强制杀死(有风险)
kill -HUP <pid>         # 通知进程重载配置
pkill -f "node server.js"     # 按命令行模式匹配杀(f 用整条命令匹配)
killall node                  # 按进程名杀(会杀所有 node,慎用)

易错 先给 kill(TERM 15),不要上来就 kill -9。TERM 允许进程保存状态、释放资源;-9 会跳过清理,可能导致数据库/文件系统不一致。若 TERM 几秒不退再 kill -9。

查找占用端口的进程

服务起不来、端口被占,从端口反查进程最直接:

ss -tlnp | grep 3000        # 谁在监听 3000(本机是 bangdream 的 Node)
ss -tlnp | grep 3306        # MySQL
ss -tlnp | grep 10086       # Xray
lsof -i :8090               # GitLab 反代端口(需安装 lsof)

易错 ss/lsof 查端口需要 root 才能显示进程名,用普通用户只看得到端口看不到 PID。ss -tlnp 的 -l 只显示监听、-t TCP、-n 不解析域名、-p 带进程。

后台任务与 nohup

手动跑脚本(如本机 cron 里的 tieba_sign.py)想放后台:

nohup /usr/bin/python3 /root/scripts/tieba_sign.py > /var/log/tieba.log 2>&1 &
# nohup 忽略 SIGHUP(关终端不杀);& 放后台;> log 重定向输出
jobs              # 查看当前 shell 的后台任务
disown %1          # 让后台任务不受 shell 退出影响

易错 nohup + & 是老式做法,生产上优先用 systemd service(能自启、能崩溃重启、开机拉起)。cron 里的任务用输出重定向 >> log 2>&1 保存日志,否则任务输出会被 cron 邮件吞掉。

案例:端口 3000 被占,bangdream 起不来

ss -tlnp | grep 3000              # 先看谁占用
pid=$(lsof -t -i:3000)            # 拿到占用的 PID
kill $pid                          # 优雅结束
systemctl start bangdream          # 再启动

易错点

  • 改完 unit 不 daemon-reload:新配置不生效。
  • enable 不等于立即启动:用 enable --now。
  • 上来就 kill -9:先 kill(TERM)让进程优雅退出。
  • 以普通用户 ss 查不到进程名:用 root。

相关命令

systemctl、ps、pgrep、pidof、top、htop、kill、pkill、killall、ss、lsof、nohup、jobs。