若把 systemd 看成一套更花哨的 init replacement,整件事很容易被看窄。那样的理解,会把争论长期停在 PID 1 这一点上;真正更有分量的设计,落在更上一层:systemd 管理的是一张由 units、排序边、activation triggers 与 cgroup 边界组成的图。[1][2][3][5] 它关心的内容,已经越过“让服务在开机时更早启动”这一层,进入了另一种目标:把进程启动、依赖建模与资源归属放进同一套系统描述里。

截至 2026-05-01T10:34:21Z UTC,公开的 systemd/systemd 仓库显示 16,259 stars、4,468 forks、3,295 个 open issues,最近一次 push 时间是 2026-05-01T10:09:22Z。[6] 公开 release 流里,v260.1 发布于 2026-03-23,此前的 v260 发布于 2026-03-17。[7] 这些数字更像维护信号,而并非门面数字:systemd 仍然以一套活跃平台组件的速度持续演进,并未沉成一块不再变化的底座石头。

配图说明:题图现在使用真实服务器机架照片,而并非开发者肖像。[9] 这个选择更贴近文章:systemd 的架构意义,来自真实 Linux 机器上的 services、sockets 与 cgroup 边界必须被协调起来,而这些机器会故障、重启,也承载生产状态。

1. 真正的抽象单位,是 unit graph

官方的 unit 文档写得很清楚,unit files 可以描述 services、sockets、devices、mounts、automounts、swaps、targets、paths、timers、slices 与 scopes。[3] bootup(7) 则把这件事继续往运行层面展开:启动流程被暴露成一组 target units,整个过程高度并行化,管理器会激活 default.target 的依赖闭包,而 default.target 通常又指向 graphical.targetmulti-user.target。[2]

最需要抓牢的一点,在于 dependency 与 ordering 是两层不同的语义。Wants=Requires= 负责把别的 units 拉进同一笔事务,After=Before= 负责决定先后顺序。[3] 一旦把这两件事压成同一个印象,systemd 的行为就会显得神秘,甚至显得任性;若把两层语义分开看,很多事情立刻清楚起来。管理器真正处理的,是一张图,而并非一份按行向下执行的 shell script。

仓库架构文档从内部也呈现出同一形状。service manager 会接收 unit files、credentials、kernel command-line settings 与 D-Bus requests;它既运行在 system mode,也运行在 per-user manager 这一层;当某个 unit 需要被启动时,执行设置会先被序列化,再由 systemd-executor 在最终 exec 之前施加 namespacing、sandboxing 与 cgroup 选项。[1] 这已经是一种更宽的设计,重心落在“用同一种语言描述并启动 Linux services”这一层。

2. socket activation 让监听端点进入模型内部

socket 文档最能说明,systemd 的问题意识已经越过单纯的 boot order。.socket unit 负责声明 listening object,与之配对的 .service unit 负责描述处理流量的 worker process。[4] 当 Accept=no 时,同一个 service 处理所有流量;当 Accept=yes 时,systemd 会按连接实例化模板 service。[4]

这条分工的意义在于,socket 本身成了由管理器持有的持久状态。Lennart Poettering 早年关于 socket activation 的文章,经由 LWN 的独立梳理,已经把价值说得很准确:它带来的重点,并不只在按需启动这一点,而落在更容易并行化、更简单的依赖处理,以及 worker process 重启时端口不用重新绑定这一层稳定性上。[8] 现行的 systemd.socket(5) 仍然保持这一模型。systemd 可以在 host network namespace 里先分配 socket,通过 sd_listen_fds() 或 inetd 风格的方式把 file descriptors 交给服务进程,同时让被激活的 service 运行在自己的 PrivateNetwork= 边界之内,仅让 activation sockets 穿过这条线。[4]

顺着这条逻辑往下看,事情就比“开机时把 daemon 拉起来”更有意思。真正接收连接的 kernel object,与负责监督、隔离、重启 worker 的策略,落在同一张图上。

3. cgroup tree 并非附属功能,而是架构的另一半

systemd 的 cgroup delegation 文档把资源模型说得很直白。整套做法建立在 cgroup v2 的两条规则之上:inner nodes 里不放 processes,以及 每个 cgroup 只有一个 writer。[5] 这两条规则一旦立住,unit types 的分工就变得非常整齐。.service.scope 是承载进程的 leaves,.slice 是树里的 branches;默认布局里,system.slice 放 system services,user.slice 放 user sessions。[5]

也正因为如此,PID 1 这一层反而不再最要紧。管理器处理的,不只是哪一个进程要被启动,还包括这些进程应当落在资源树的什么位置,以及谁有资格去改写那棵树。single-writer 规则对容器管理器或嵌套 supervisor 尤其重要。只要别的系统去修改 systemd 认定属于自己的那片 subtree,整台机器的可组合性就会迅速下降,最后演成一场归属冲突。[5]

换个角度看,systemd 的架构只有在“startup、supervision 与 resource placement 是同一个问题”这一前提下才会彻底通顺。若把 cgroup 这一半从脑中拿掉,它许多强烈的判断就会显得过于用力;把整套模型放回原位,那些判断就更像护栏。

4. 真正有用的问题,在于你是否要让同一个管理器接管整张图

到了这里,适配边界会清楚许多。systemd 最适合的,是那些 Linux-first 的运行环境:团队愿意让同一个原生管理器接管 unit definition、boot targets、activation sockets、restart policy 与顶层 cgroup tree。[1][2][4][5] 当 service 数量已经多到依赖边真实存在,当 per-user managers、按需监听器或资源切片确实在日常运维中发挥作用时,这套设计会很有力量。

另一类环境里,它的优势会收得更窄一些。若场景本身追求极简,若跨越非-systemd Unix 系统的可移植性比 Linux 原生整合更重要,或若 service model 本来就小到一张图管理器带来的机械感超过收益,那么 systemd 的分量就会显得偏重。这是一笔架构取舍,与文化站队无关。

仓库活动也在提示,这里讨论的是一块仍在持续变化的平台表面,而并非一组被冻结的底层管道。公开仓库与 release 流持续更新,这一点对于那些直接建立在 unit semantics、activation rules 或 cgroup behavior 之上的团队尤其重要。[6][7] 因而,真正值得问的问题,并不在于 systemd 是否“赢了”,而在于你的 Linux estate 是否真的受益于让一个管理器从头到尾接管整张图。

结尾

在 2026 年理解 systemd,最有效的方式,不宜停在“它是一套有争议的 boot replacement”这一层。更准确的读法,是把它视为一套把三件事合并起来的 Linux service manager:dependency graphs、activation points 与 resource ownership。[1][2][4][5] Units 用来描述状态,targets 提供 boot 与 session 的结构,socket activation 让 listeners 在 worker 生命周期变化时仍保持稳定,slices、scopes 与 services 则把这些状态落进 cgroup tree。

当这套架构被看清之后,取舍关系也会随之清楚。若你希望同一个管理器接管整张图,systemd 的一致性很强;若你的问题并不用这张图,它的判断就会持续显得偏重。

来源

  1. systemd.io,《The systemd Repository Architecture》—— service manager 的输入、per-user managers、systemd-executor,以及围绕 unit 处理的内部代码结构。
  2. freedesktop.org,bootup(7) —— 以 target 为中心的启动结构、default.target,以及高度并行化的启动模型。
  3. freedesktop.org,systemd.unit(5) —— unit types、load paths,以及 Wants= / Requires= 这类依赖指令与 After= / Before= 这类排序指令之间的区别。
  4. freedesktop.org,systemd.socket(5) —— socket units、Accept=yes / Accept=no、descriptor passing,以及被激活服务的 namespace 边界。
  5. systemd.io,《Control Group APIs and Delegation》—— cgroup v2 设计规则、slice/service/scope 的角色、unified hierarchy 与 single-writer ownership。
  6. GitHub API,systemd/systemd 仓库元数据快照 —— 文章写作时的 stars、forks、open issues 与最近 push 活动。
  7. GitHub,systemd/systemd releases —— 当前 release 流,包括 v260.1v260
  8. LWN.net,《systemd for administrators, Part XI: socket activation》—— 来自独立媒体的说明,解释 socket activation 为依赖处理与重启行为带来的结构优势。
  9. Wikimedia Commons,“File:Servers in a Rack.jpg”——本文题图所用真实服务器机架照片来源页。