systemd:单元依赖和顺序

欢迎回到我们关于 systemd 功能的后续系列。 正如您从我们之前的文章中猜到的那样,systemd 为服务启动和管理带来了更多的功能和灵活性。 systemd 与传统相比最重要的变化之一 系统初始化 是它如何启动单位。

您可能从普通用户那里听说过 systemd 会一起启动所有内容。 有些人认为这是真的,这就是系统启动速度更快的原因。 但事实并非如此简单。 让我们更深入地了解一下 systemd 是如何理解单元关系的。

单元依赖

单元文件包含依赖的特性。 任何单元都可能需要或需要一个或多个其他单元才能运行。 这些依赖项使用指令在单元文件中设置 想要需要. 这些之间的区别很简单。

  • 如果 unit1 有 Wants=unit2 作为依赖,当 unit1 运行时,unit2 也会运行。 但是unit2是否启动成功不影响unit1运行成功。
  • 然而,当 unit1 的 Requires=unit2 时,两个单元都会再次运行,但如果 unit2 不成功,则 unit1 也会被停用。 无论 unit1 的进程是否可以正常工作,都会发生这种情况。

你注意到这个描述有什么微妙之处吗? 它没有谈论秩序。 当 systemd 启动您的系统时,它会加载所有单元文件并读取它们以确定这样的依赖关系。 在这些示例中运行 unit1 时,会运行 unit2 同时. 重要的是要知道依赖关系和排序对于 systemd 来说是两个不同的东西。

这是一个 example 部分 sshd.service 单元文件中的依赖项:

Wants=sshd-keygen.service

所以当 sshd.service 运行时,sshd-keygen.service 也会运行。 但是,sshd-keygen.service 不需要成功,sshd.service 也能成功运行。

为什么需要存在这样的依赖项? 在这种情况下,sshd-keygen.service 会为服务器创建新的 SSH 密钥(如果它们不存在)。 我们总是想在 SSH 服务器启动之前检查这些密钥是否存在。 如果它们已经存在,则服务单元退出并显示错误信息。 但当然,在这种情况下,我们仍然希望 SSH 服务器像往常一样运行。

单位订单

这并不意味着 systemd 不能把事情按正确的顺序排列。 没有任何其他指令,systemd 将同时运行一组单元。 这可能就是为什么有些人认为 systemd 在同一时间(或“并行”)启动所有内容的原因。 当然,有时有必要让进程按特定顺序运行。

幸运的是,systemd 也有针对这个问题的单元指令, . 这些指令的工作方式与您预期的差不多:

  • 如果 unit1 具有指令 Before=unit2,那么如果两个单元都运行,则 unit1 将在 unit2 启动之前完全执行。
  • 如果 unit1 具有指令 After=unit2,则如果两个单元都运行,则 unit2 将在 unit1 启动之前完全执行。

再次注意,这种排序不会影响依赖关系。 这两种情况都不会导致 unit2 运行。 我们再来看看 sshd.service 单元:

Wants=sshd-keygen.service
After=network.target sshd-keygen.service

排序指令 After 确保 SSH 服务器在主机密钥生成单元之后以及网络启动之后才会运行。 (network.target 单元确保各个单元启动网络。)像 Wants 和 Requires 这样的依赖项经常与 After 一起使用,以保持适当的依赖项和顺序。

更快的启动时间

您可能还记得在本系列前面的文章中,SysVinit 根据编号按顺序启动每个服务。 但是,systemd 会自动对单元文件进行排序以读取依赖关系和排序信息。 它使用此信息允许许多服务几乎同时启动,同时在需要的地方保持顺序。

这种处理是在 systemd 下启动速度更快的原因之一。 更快的启动时间并不是发明 systemd 的主要原因,但它通常是它处理单元的方式的一个附带好处。