这是《Linux 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。
systemd 是多数主流 Linux 发行版的 init 系统和服务管理器。它负责启动服务、管理依赖、收集日志、限制资源、隔离进程树。现代后端服务应优先使用 systemd 或容器编排,而不是手工 nohup。
9.1 systemd 组成
systemd
|-- systemd(1) 主进程
|-- unit 配置
|-- journald 日志
|-- logind 登录管理
|-- timedated 时间管理
+-- cgroup 资源分组
查看:
ps -p 1 -o pid,comm,args
systemctl --version
systemctl --no-pager --type=service
9.2 常用 systemctl 命令
服务:
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx
sudo systemctl try-restart nginx
sudo systemctl enable nginx
sudo systemctl disable nginx
sudo systemctl daemon-reload
状态:
systemctl status nginx
systemctl is-active nginx
systemctl is-enabled nginx
systemctl list-units --type=service
systemctl list-units --failed
systemctl list-unit-files --type=service
查看配置:
systemctl cat nginx
systemctl show nginx
systemctl show nginx -p MainPID -p ActiveState -p SubState
修改配置后:
sudo systemctl daemon-reload
sudo systemctl restart app
daemon-reload 重新读取单元文件,不等于重启服务。
9.3 Unit 类型
| 类型 | 后缀 | 用途 |
|---|---|---|
| service | .service |
服务 |
| socket | .socket |
socket 激活 |
| timer | .timer |
定时任务 |
| target | .target |
一组 unit |
| mount | .mount |
挂载 |
| path | .path |
路径变化触发 |
| slice | .slice |
资源分组 |
单元路径:
/etc/systemd/system 管理员配置,优先级高
/run/systemd/system 运行时配置
/usr/lib/systemd/system 软件包安装
覆盖配置推荐使用:
systemctl edit nginx
它会生成 drop-in 文件,避免直接修改包管理的原始单元。
9.4 服务单元示例
[Unit]
Description=Order Service
Documentation=https://example.internal/docs/order
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=app
Group=app
WorkingDirectory=/opt/order
Environment=JAVA_OPTS=-Xms1g -Xmx1g
EnvironmentFile=-/etc/order/env
ExecStart=/usr/bin/java $JAVA_OPTS -jar app.jar
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
TimeoutStartSec=60s
TimeoutStopSec=30s
KillSignal=SIGTERM
KillMode=mixed
LimitNOFILE=65535
UMask=0027
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/var/log/order /opt/order/data
[Install]
WantedBy=multi-user.target
安装:
sudo cp order.service /etc/systemd/system/order.service
sudo systemctl daemon-reload
sudo systemctl enable --now order.service
9.5 Type 与启动状态
| Type | 判定方式 |
|---|---|
| simple | ExecStart 启动即认为主进程启动 |
| exec | ExecStart 执行成功后进入启动 |
| forking | 子进程分离,依赖 PIDFile 或推断 |
| notify | 应用主动调用 sd_notify |
| oneshot | 一次性任务,退出后进入 inactive 或 dead |
Java 应用常使用:
Type=simple
ExecStart=/usr/bin/java -jar app.jar
需要等待就绪时,可用 Type=notify,但应用必须支持 sd_notify;也可通过健康检查系统处理,而不是让 systemd 猜测业务就绪。
9.6 依赖关系
[Unit]
Wants=network-online.target
After=network-online.target
Requires=postgresql.service
BindsTo=nginx.service
语义:
| 指令 | 行为 |
|---|---|
| Wants | 弱依赖,失败也启动自己 |
| Requires | 强依赖,被依赖失败则自己失败 |
| Requisite | 必须已激活,否则不启动 |
| BindsTo | 自己随被依赖停止 |
| After | 在指定 unit 后启动 |
| Before | 在指定 unit 前启动 |
After 只定义顺序,不自动创建依赖。需要同时写 Requires 或 Wants。
9.7 重启策略
Restart=no
Restart=on-success
Restart=on-failure
Restart=always
Restart=on-abnormal
Restart=on-watchdog
常用:
Restart=on-failure
RestartSec=5s
StartLimitIntervalSec=60s
StartLimitBurst=5
如果服务不断崩溃,自动重启只是掩盖问题。应检查退出原因、资源限制和依赖状态。
查看失败:
systemctl status app
journalctl -u app -n 200
systemctl show app -p Result -p ExecMainStatus
9.8 资源限制
文件与进程:
LimitNOFILE=65535
LimitNPROC=4096
LimitCORE=infinity
CPU 与内存:
CPUWeight=100
CPUQuota=200%
MemoryHigh=4G
MemoryMax=6G
TasksMax=1024
查看:
systemctl show app -p MemoryMax -p CPUQuota -p TasksMax
cat /proc/$(systemctl show -p MainPID --value app)/limits
内存硬限制达到时,内核可能杀掉进程;限制应低于机器容量,并保留系统余量。
9.9 journald 日志
查看服务日志:
journalctl -u nginx
journalctl -u nginx -f
journalctl -u nginx -n 100 --no-pager
journalctl -u nginx --since today
journalctl -u nginx --since '2026-08-25 10:00' --until '2026-08-25 11:00'
按优先级:
journalctl -p err
journalctl -p warning -u app
按 PID:
journalctl _PID=<pid>
查看磁盘占用:
journalctl --disk-usage
清理:
sudo journalctl --vacuum-time=14d
sudo journalctl --vacuum-size=2G
长期配置:
# /etc/systemd/journald.conf
[Journal]
Storage=persistent
SystemMaxUse=2G
MaxRetentionSec=30day
9.10 Timer 定时任务
示例 /etc/systemd/system/backup.service:
[Unit]
Description=Nightly Backup
[Service]
Type=oneshot
User=backup
ExecStart=/opt/scripts/backup.sh
示例 /etc/systemd/system/backup.timer:
[Unit]
Description=Run backup nightly
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
启用:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer
相比 crontab,timer 更容易纳入 systemd 依赖、日志和资源控制。
9.11 排障案例
服务启动失败
systemctl status app --no-pager
journalctl -u app -n 200 --no-pager
systemctl cat app
sudo -u app /opt/app/bin/start --check
ss -lntp
常见原因:
- ExecStart 路径错误;
- User 无权限;
- 配置不存在;
- 环境变量缺失;
- 端口冲突;
- 单元语法错误;
- 依赖未就绪。
修改单元不生效
systemctl cat app
sudo systemctl daemon-reload
sudo systemctl restart app
检查是否被 drop-in 覆盖:
systemctl show app -p FragmentPath -p DropInPaths
服务被 OOM 杀掉
journalctl -u app --since today
dmesg -T | grep -i 'out of memory'
systemctl show app -p MemoryMax
处理:
- 区分 cgroup 限制和机器内存;
- 检查内存泄漏;
- 调整应用内存参数;
- 评估扩容;
- 增加水位监控。
本章小结
systemd 用 unit 描述服务,用依赖控制启动顺序,用 cgroup 管资源,用 journald 收日志。生产服务应显式配置用户、目录、环境、重启策略、停止超时、文件数限制和日志留存。修改单元后要 daemon-reload,并用状态、日志和业务健康检查闭环。
思考题
daemon-reload和restart有什么区别?Wants、Requires和After分别解决什么问题?Restart=always可能掩盖什么问题?- systemd timer 相比 crontab 有哪些优势?
- 为 Java 服务写一个包含资源限制和优雅停机的 unit。