第 5 章 · 进程、服务与 systemd
本章目标:分清进程和服务;读懂 ps 输出;用 systemctl 启动、停止、设置开机自启;亲手写一份 unit 文件托管 shop-demo 小服务;服务挂了知道从哪查原因。
学时建议:3.5~4 小时(含 2 小时跟练)
前置:完成 linux-shell ch04;本机有 sudo 权限。
5.1 场景说明:为什么 go run 不能上生产
你在 ch04 里用 grep 查 api-go-demo 日志,发现服务在报错。开发同事说:「我本地 go run 好好的啊。」
上线后常见情况是:
- 终端一关,程序就没了(没有守护)
- 服务器重启后,没人手动再启动
- 进程崩了,不会自动拉起来
systemd 就是 Ubuntu 上管这件事的标准工具:把程序登记成「服务」,开机自启、崩溃重启、统一看日志。
开发机:go run main.go → 人盯着,关窗口就停
生产机:systemctl start api-go-demo → 系统托管,重启后仍在
5.2 先搞懂两个词:进程 vs 服务
| 概念 | 是什么 | 你怎么看到它 |
|---|---|---|
| 进程 | 正在内存里跑的一个程序实例 | ps、top |
| 服务 | 被 systemd 登记、按规则启停的程序 | systemctl status xxx |
一个服务背后通常有一个(或多个)进程。你可以有很多进程不是服务(比如你刚开的 bash);但要上生产的 api-go-demo,必须变成服务。
5.3 跟练:第一次看进程
打开终端,依次输入:
ps aux | head -5
ps aux | grep ssh | grep -v grep
pgrep -a ssh
你应该看到什么:
- 第一行是表头:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND grep ssh那行类似:root 1234 ... sshd: /usr/sbin/sshd -D ...pgrep -a ssh只打印 PID 和命令,更干净
读懂关键列:
| 列 | 含义 | 排查时怎么用 |
|---|---|---|
| USER | 以哪个用户身份跑 | 权限问题看这里(ch03) |
| PID | 进程号 | kill、查端口占用时用 |
| STAT | 状态(S 睡眠、R 运行、Z 僵尸…) | 僵尸进程要查父进程 |
| COMMAND | 实际执行的命令 | 确认是不是你要的程序 |
为什么 先学 ps 再学 systemctl:服务 failed 时,status 里会告诉你 PID 和最后执行的命令,不会看 ps 你会懵。
5.4 跟练:用 top 动态观察(可选)
top
操作:看几秒后按 q 退出(不是 Ctrl+C)。
你应该看到:CPU、内存占用前几名的进程在跳。生产上一般不用 top 长期开着,但要知道:某个服务 CPU 100% 可能是死循环。
终止进程(教学环境练手,不要对 sshd 动手):
# 仅演示:先 sleep 后台跑,再 kill
sleep 300 &
echo "PID=$!"
kill -15 $! # 优雅终止,等同 SIGTERM
为什么 -15 优先于 -9:给程序机会保存数据、关连接;-9 强杀,可能丢数据。
5.5 systemd 是什么、unit 文件在哪
Ubuntu 22.04 用 systemd 做「PID 1」——所有进程的祖宗,负责拉起其它服务。
systemctl status ssh
systemctl is-active ssh
systemctl is-enabled ssh
你应该看到(ssh 正常时):
Active: active (running)— 正在跑is-active输出activeis-enabled输出enabled或disabled(是否开机自启)
unit 文件位置(记路径,ch14 写 api-go-demo 要用):
| 路径 | 谁写的 |
|---|---|
/lib/systemd/system/ | 系统包安装自带 |
/etc/systemd/system/ | 管理员自定义(我们写这里) |
列出正在跑的服务:
systemctl list-units --type=service --state=running | head -15
5.6 systemctl 命令表(先背这 8 个)
| 命令 | 干什么 | 什么时候用 |
|---|---|---|
start | 启动 | 部署完第一次拉起来 |
stop | 停止 | 维护、换二进制前 |
restart | 先停再启 | 改配置后 |
status | 看状态+最近日志 | 排错第一步 |
enable | 开机自启 | 上线前必做 |
disable | 取消自启 | 下线服务 |
daemon-reload | 重读 unit 文件 | 改完 .service 必做 |
is-active / is-enabled | 脚本里检查 | 自动化部署脚本 |
常见坑:改完 /etc/systemd/system/xxx.service 直接 start,报 Unit not found 或行为不对——必须先 sudo systemctl daemon-reload。
5.7 跟练:写一个真正能跑的 shop-demo 服务
前面 echo 示例太假,这次写一个循环打印日志的小脚本,更接近真实服务。
步骤 1 — 写脚本:
mkdir -p ~/dev-workspace/shop-demo/scripts
cat > ~/dev-workspace/shop-demo/scripts/heartbeat.sh << 'EOF'
#!/usr/bin/env bash
while true; do
echo "$(date -Iseconds) shop-demo heartbeat ok"
sleep 5
done
EOF
chmod +x ~/dev-workspace/shop-demo/scripts/heartbeat.sh
步骤 2 — 写 unit 文件(逐段理解):
sudo tee /etc/systemd/system/shop-demo-heartbeat.service << 'EOF'
[Unit]
Description=Shop Demo Heartbeat (teaching)
After=network.target
[Service]
Type=simple
ExecStart=/home/PLACEHOLDER/dev-workspace/shop-demo/scripts/heartbeat.sh
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
重要:把上面 PLACEHOLDER 换成你的 Linux 用户名。查用户名: