Linux systemd 发展演进与实战指南
本文说明 systemd 为何成为主流 init/系统管理框架,梳理 SysVinit、Upstart 与 systemd 的演进关系,并给出工作原理、常用命令与典型单元文件解析。
目录
- [一、背景:systemd 为何成为主流](#一、背景:systemd 为何成为主流)
- [二、三代 init 要解决什么问题](#二、三代 init 要解决什么问题)
- 三、发展简史
- 四、工作原理
- 五、启动流程概览
- [六、日常使用:systemctl / target / journalctl](#六、日常使用:systemctl / target / journalctl)
- [七、自定义 .service 示例](#七、自定义 .service 示例)
- [八、案例:nginx.service 单元解析](#八、案例:nginx.service 单元解析)
- 九、三代方案对比表
一、背景:systemd 为何成为主流
在 systemd 普及之前,Linux 多使用 SysVinit (串行启动、效率低)和 Upstart(事件驱动、并行更好,但设计复杂、与旧脚本兼容成本高)。
systemd 由 Lennart Poettering、Kay Sievers 等推动,目标:更快、能力更强、接口更统一,2010 年代起逐渐成为 Fedora、Ubuntu、Debian、RHEL/CentOS、openSUSE 等发行版默认 init。
| 维度 | 要点 |
|---|---|
| 启动快 | 依赖图并行启动;Socket/D-Bus 按需激活(如首次连 22 端口再拉起 sshd) |
| 管理统一 | 服务、挂载、定时器等抽象为 Unit,取代零散 init 脚本 |
| 功能集成 | 内置 journald (日志)、networkd (网络)、udev (设备)、cgroups(资源)等 |
| 迁移成本 | 可兼容 SysVinit 脚本,平滑过渡 |
二、三代 init 要解决什么问题
三者都在解决同一问题:内核把控制权交给 PID 1 之后,如何把网络、存储、服务、运行级别等按正确顺序、高效拉起来,并在关机时有序收尾。
| 代际 | 角色概括 |
|---|---|
| SysVinit | 「清单式」管家:/etc/init.d/ + rcX.d 符号链接,按运行级别串行跑脚本 |
| Upstart | 「事件驱动」管家:网卡就绪、磁盘就绪等事件触发任务,可并行,但模型复杂、生态未统一 |
| systemd | 「系统级 CEO」:一切皆 Unit,PID 1 统一调度;并行 + 按需激活 + 日志/网络等一体化 |
SysVinit 典型痛点:串行慢;不维护服务「是否在跑」;改启动项要折腾链接;只管启停,不管日志与依赖表达。
Upstart 典型痛点:事件规则难调试;与 SysV 脚本折中导致设计不纯粹;未形成日志、设备等统一管理平台。
systemd 的定位 :不仅是启动器,而是系统管理框架 ,对外 largely systemctl / journalctl 一致接口。
三、发展简史
2010 左右 systemd 项目启动
2011 Fedora 15 首个主流发行版默认 systemd
2012--2014 Arch、CoreOS 等跟进;Ubuntu 15.04 弃 Upstart 转 systemd
2014 Debian 技术委员会决议 Jessie 采用 systemd → 主流格局基本确定
现今 多数服务器/桌面发行版默认 systemd
四、工作原理
4.1 架构要点
- PID 1 :
systemd回收僵尸进程、关机时按序结束子进程。 - 家族进程 :
systemd-journald、systemd-networkd、systemd-resolved、systemd-udevd等与 PID 1 协同。
4.2 单元类型(Unit)
| 后缀 | 作用 |
|---|---|
.service |
守护进程(如 nginx、sshd) |
.socket |
套接字,常用于 Socket 激活 |
.mount / .automount |
挂载 / 自动挂载 |
.timer |
定时任务(可替代部分 cron 场景) |
.target |
单元组,对应传统「运行级别」逻辑 |
配置文件一般为 INI 风格 ,路径多在 /lib/systemd/system/、/etc/systemd/system/。
4.3 并行启动与按需激活
- 并行 :根据
After/Before/Requires/Wants建依赖图,无依赖的单元可同时启动。 - Socket 激活 :先由
.socket监听端口;首个连接到达再启动.service,空闲后可停服务,省资源。
4.4 依赖关键字(简表)
| 指令 | 含义 |
|---|---|
After= / Before= |
启动顺序先后(不必然强绑定成败) |
Requires= |
强依赖:被依赖单元失败则本单元失败 |
Wants= |
弱依赖:被依赖失败本单元仍尝试启动 |
Conflicts= |
互斥,不可同时 active |
常见目标:multi-user.target(多用户文本)、graphical.target(图形会话)。
五、启动流程概览
内核执行 /sbin/init(通常指向 systemd)
→ 扫描并加载 Unit,解析依赖图
→ 按 default.target(如 multi-user.target)并行拉起所需单元
→ 运行期监控服务,按配置自动重启等
六、日常使用:systemctl / target / journalctl
6.1 服务(.service)
bash
sudo systemctl start nginx # 启动(可写 nginx.service)
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx # 不中断主进程的 reload(视服务支持)
sudo systemctl status nginx # 状态 + 近期日志片段
sudo systemctl enable nginx # 开机自启
sudo systemctl disable nginx
systemctl is-enabled nginx
6.2 Target 与电源
bash
systemctl get-default
sudo systemctl set-default multi-user.target
sudo systemctl set-default graphical.target
sudo systemctl isolate multi-user.target # 切换当前 target(如图形→多用户)
sudo systemctl poweroff
sudo systemctl reboot
sudo systemctl suspend
6.3 日志 journalctl
bash
sudo journalctl # 全部
sudo journalctl -b # 本次启动以来
sudo journalctl -f # 跟随
sudo journalctl -u nginx.service
sudo journalctl -p err # 优先级过滤
sudo journalctl -u nginx -b -p err
七、自定义 .service 示例
文件:/etc/systemd/system/my_app.service
ini
[Unit]
Description=My Custom Python App
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/my_app
ExecStart=/usr/bin/python3 /opt/my_app/my_app.py
Restart=on-failure
[Install]
WantedBy=multi-user.target
bash
sudo systemctl daemon-reload
sudo systemctl start my_app
sudo systemctl enable my_app
八、案例:nginx.service 单元解析
以下结构与 Debian/Ubuntu 常见包内单元一致,具体以本机 systemctl cat nginx 为准。
ini
[Unit]
Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
After=network.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true
[Install]
WantedBy=multi-user.target
| 段/项 | 说明 |
|---|---|
| Description / Documentation | status 展示;文档入口 |
| After=... | 在网络、远程文件系统、NSS 等就绪后再启 |
| Wants=network-online.target | 弱依赖「网络真正可用」 |
| Type=forking | 主进程 fork 后台化;需 PIDFile 让 systemd 跟踪 master |
| ExecStartPre | -t 先测配置,失败则不启动 |
| ExecReload | 对应 systemctl reload,平滑重载 |
| ExecStop | 优雅退出(如 QUIT),- 前缀表示失败不致命 |
| KillMode=mixed | 停服时对主进程与其它 cgroup 进程的组合策略 |
| PrivateTmp=true | 独立 /tmp,减小横向影响 |
| WantedBy=multi-user.target | enable 时在 multi-user.target.wants/ 建链,进入多用户目标时拉起 |
九、三代方案对比表
| 特性 | SysVinit | Upstart | systemd |
|---|---|---|---|
| 核心模型 | 串行脚本 | 事件驱动 | 单元依赖图 + 并行 |
| 启动速度 | 慢 | 较快 | 通常更快 |
| 管理方式 | 分散脚本 | 集中事件配置 | Unit + systemctl 统一 |
| 功能范围 | 基本启停 | 启停 + 部分事件 | 服务、日志、网络、设备等 |
| 设计取向 | 简单、可移植 | 缓解启动瓶颈 | 高效、统一、功能全 |
根据公开资料与常见发行版行为整理;具体行为以本机 systemd 版本与单元文件为准。