分析 Linux 启动性能

使用 systemd-analyze 来深入了解并解决 Linux 启动性能问题。
90 位读者喜欢这篇文章。
How to find files in Linux

Lewis Cowles, CC BY-SA 4.0

系统管理员的工作之一是分析系统的性能,并查找和解决导致性能不佳和启动时间过长的问题。系统管理员还需要检查 systemd 配置和用法的其他方面。

systemd init 系统提供了 systemd-analyze 工具,可以帮助发现性能问题和其他重要的 systemd 信息。在之前的文章 分析 systemd 日历和时间跨度 中,我使用 systemd-analyze 来分析 systemd 计时器中的时间戳和时间跨度,但此工具还有许多其他用途,我将在本文中探讨其中一些用途。

启动概述

Linux 启动序列是开始探索的好地方,因为许多 systemd-analyze 工具功能都针对启动。但首先,重要的是要了解引导和启动之间的区别。引导序列从 BIOS 通电自检 (POST) 开始,到内核完成加载并接管主机系统时结束,这标志着启动的开始以及 systemd 日志开始的时间点。

在本系列文章的第二篇 了解 Linux 上的 systemd 启动 中,我更详细地讨论了启动,包括发生了什么以及按什么顺序发生。在本文中,我想检查启动序列,以查看完成启动所花费的时间以及哪些任务花费的时间最多。

我将在下面展示的结果来自我的主工作站,这比虚拟机的结果更有趣。该工作站由 ASUS TUF X299 Mark 2 主板、Intel i9-7960X CPU(具有 16 个内核和 32 个 CPU(线程))和 64GB RAM 组成。以下某些命令可以由非 root 用户运行,但我在本文中将使用 root 用户,以避免在用户之间切换。

有几种选项可以检查启动序列。systemd-analyze 命令的最简单形式是显示启动的每个主要部分(内核启动、加载和运行 initrd(即初始 ramdisk,用于初始化某些硬件和挂载 / [根] 文件系统的临时系统映像)以及用户空间(加载使主机进入可用状态所需的所有程序和守护程序的地方))中花费的时间的概述。如果未将子命令传递给该命令,则暗示 systemd-analyze time

[root@david ~]$ systemd-analyze 
Startup finished in 53.921s (firmware) + 2.643s (loader) + 2.236s (kernel) + 4.348s (initrd) + 10.082s (userspace) = 1min 13.233s 
graphical.target reached after 10.071s in userspace
[root@david ~]#

此输出中最值得注意的数据是固件 (BIOS) 中花费的时间:几乎 54 秒。这是一个非常长的时间,我的其他物理系统中没有一个花费如此长的时间才能完成 BIOS。

我的 System76 Oryx Pro 笔记本电脑在 BIOS 中仅花费 8.506 秒,而我所有自组装的系统都花费不到 10 秒。在进行了一些在线搜索后,我发现这款主板以其异常长的 BIOS 启动时间而闻名。我的主板永远不会“直接启动”。它总是挂起,我需要执行断电/通电循环,然后 BIOS 启动并显示错误,我需要按 F1 进入 BIOS 配置,从中我可以选择启动驱动器并完成启动。这就是额外时间的来源。

并非所有主机都显示固件数据。我的非科学实验让我相信,此数据仅针对 Intel 第 9 代或更高版本的处理器显示。但这可能是不正确的。

此启动过程的概述很有趣,并提供了良好(尽管有限)的信息,但还有更多关于启动的信息可用,我将在下面介绍。

归咎

您可以使用 systemd-analyze blame 来发现哪些 systemd 单元花费的时间最多来初始化。结果按它们初始化所花费的时间顺序显示,从最多到最少

[root@david ~]$ systemd-analyze blame                                                                         
       5.417s NetworkManager-wait-online.service                                                       
       3.423s dracut-initqueue.service                                                                 
       2.715s systemd-udev-settle.service                                                              
       2.519s fstrim.service                                                                           
       1.275s udisks2.service                                                                          
       1.271s smartd.service                                                                           
        996ms upower.service                                                                           
        637ms lvm2-monitor.service                                                                     
        533ms lvm2-pvscan@8:17.service                                                                 
        520ms dmraid-activation.service                                                                
        460ms vboxdrv.service                                                                          
        396ms initrd-switch-root.service
<SNIP – removed lots of entries with increasingly small times>

由于许多服务并行启动,因此这些数字的总和可能明显大于 systemd-analyze time 给出的 BIOS 之后所有内容的总时间。所有这些都是小数字,因此我在这里找不到任何显着的节省。

此命令的数据可以提供关于您可能考虑改进启动时间的服务的指示。可以禁用未使用的服务。在此启动序列期间,似乎没有任何单个服务花费过多的时间。您可能会看到每次启动和启动的不同结果。

关键链

就像项目管理中的关键路径一样,关键链显示了启动期间发生的时间关键事件链。这些是您在启动速度较慢时想要查看的 systemd 单元,因为它们是导致延迟的单元。此工具不显示所有启动的单元,仅显示此关键事件链中的单元

[root@david ~]# systemd-analyze critical-chain 
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

graphical.target @10.071s
└─lxdm.service @10.071s
  └─plymouth-quit.service @10.047s +22ms
    └─systemd-user-sessions.service @10.031s +7ms
      └─remote-fs.target @10.026s
        └─remote-fs-pre.target @10.025s
          └─nfs-client.target @4.636s
            └─gssproxy.service @4.607s +28ms
              └─network.target @4.604s
                └─NetworkManager.service @4.383s +219ms
                  └─dbus-broker.service @4.434s +136ms
                    └─dbus.socket @4.369s
                      └─sysinit.target @4.354s
                        └─systemd-update-utmp.service @4.345s +9ms
                          └─auditd.service @4.301s +42ms
                            └─systemd-tmpfiles-setup.service @4.254s +42ms
                              └─import-state.service @4.233s +19ms
                                └─local-fs.target @4.229s
                                  └─Virtual.mount @4.019s +209ms
                                    └─systemd-fsck@dev-mapper-vg_david2\x2dVirtual.service @3.742s +274ms
                                      └─local-fs-pre.target @3.726s
                                        └─lvm2-monitor.service @356ms +637ms
                                          └─dm-event.socket @319ms
                                            └─-.mount
                                              └─system.slice
                                                └─-.slice
[root@david ~]#

@ 开头的数字显示自启动开始以来单元变为活动状态时的绝对秒数。以 + 开头的数字显示单元启动所需的时间。

系统状态

有时您需要确定系统的当前状态。systemd-analyze dump 命令转储关于当前系统状态的大量数据。它以主要启动时间戳列表、每个 systemd 单元的列表以及每个单元状态的完整描述开始

[root@david ~]# systemd-analyze dump
Timestamp firmware: 1min 7.983523s
Timestamp loader: 3.872325s
Timestamp kernel: Wed 2020-08-26 12:33:35 EDT
Timestamp initrd: Wed 2020-08-26 12:33:38 EDT
Timestamp userspace: Wed 2020-08-26 12:33:42 EDT
Timestamp finish: Wed 2020-08-26 16:33:56 EDT
Timestamp security-start: Wed 2020-08-26 12:33:42 EDT
Timestamp security-finish: Wed 2020-08-26 12:33:42 EDT
Timestamp generators-start: Wed 2020-08-26 16:33:42 EDT
Timestamp generators-finish: Wed 2020-08-26 16:33:43 EDT
Timestamp units-load-start: Wed 2020-08-26 16:33:43 EDT
Timestamp units-load-finish: Wed 2020-08-26 16:33:43 EDT
Timestamp initrd-security-start: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-security-finish: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-generators-start: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-generators-finish: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-units-load-start: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-units-load-finish: Wed 2020-08-26 12:33:38 EDT
-> Unit system.slice:
        Description: System Slice
        Instance: n/a
        Unit Load State: loaded
        Unit Active State: active
        State Change Timestamp: Wed 2020-08-26 12:33:38 EDT
        Inactive Exit Timestamp: Wed 2020-08-26 12:33:38 EDT
        Active Enter Timestamp: Wed 2020-08-26 12:33:38 EDT
        Active Exit Timestamp: n/a
        Inactive Enter Timestamp: n/a
        May GC: no
<SNIP – Deleted a bazillion lines of output>

在我的主工作站上,此命令生成了 49,680 行和大约 1.66MB 的数据流。此命令非常快,因此您无需等待结果。

 

我非常喜欢为各种连接的设备(例如存储)提供的丰富细节。每个 systemd 单元都有一个部分,其中包含详细信息,例如各种运行时的模式、缓存和日志目录、用于启动单元的命令行、进程 ID (PID)、启动时间戳以及内存和文件限制。

 

systemd-analyze 的手册页显示了 systemd-analyze --user dump 选项,该选项旨在显示有关用户管理器内部状态的信息。这对我的情况失败了,互联网搜索表明可能存在问题。在 systemd 中,--user 实例用于管理和控制属于每个用户的进程层次结构的资源。每个用户的进程都是控制组的一部分,我将在以后的文章中介绍。

分析图

大多数尖头老板 (PHB) 和许多优秀的经理发现漂亮的图形比我通常更喜欢的基于文本的系统性能数据更容易阅读和理解。但是,有时,即使我也喜欢好的图形,systemd-analyze 也提供了以 SVG 矢量图形图表显示启动数据的能力。

以下命令生成一个矢量图形文件,该文件显示了引导和启动期间发生的事件。生成此文件仅需几秒钟

[root@david ~]# systemd-analyze plot > /tmp/bootup.svg

此命令创建一个 SVG,它是一个文本文件,定义了一系列图形矢量,应用程序(包括图像查看器、Ristretto、Okular、Eye of Mate、LibreOffice Draw 等)使用这些矢量来生成图形。这些应用程序处理 SVG 文件以创建图像。

我使用 LibreOffice Draw 渲染了一个图形。该图形非常大,您需要大幅放大才能看清任何细节。这是其中的一小部分

 

启动序列位于图形时间轴上的零 (0) 的左侧,而启动序列位于零的右侧。这一小部分显示了内核、initrd 以及 initrd 启动的进程。

此图一目了然地显示了什么时间启动、启动需要多长时间以及主要依赖项。关键路径以红色突出显示。

另一个生成图形输出的命令是 systemd-analyze dot。它以 DOT 格式生成文本依赖关系图描述。然后将生成的数据流通过 dot 实用程序进行管道传输,该实用程序是一系列程序的一部分,可用于从各种类型的数据生成矢量图形文件。这些 SVG 文件也可以由上面列出的工具处理。

首先,生成文件。这在我的主工作站上花费了将近九分钟

[root@david ~]# time systemd-analyze dot | dot -Tsvg > /tmp/test.svg
   Color legend: black     = Requires
                 dark blue = Requisite
                 dark grey = Wants
                 red       = Conflicts
                 green     = After

real    8m37.544s
user    8m35.375s
sys     0m0.070s
[root@david ~]#

我不会在此处重现输出,因为生成的图形非常像意大利面条。但您应该尝试一下并查看结果,以了解我的意思。

条件

我在阅读 systemd-analyze(1) 手册页时发现的一个更有趣但有些通用的功能是 condition 子命令。(是的——我确实阅读了手册页,并且我从中学习到了惊人的知识!)此 condition 子命令可用于测试可在 systemd 单元文件中使用的条件和断言。

它也可以在脚本中用于评估一个或多个条件——如果所有条件都满足,则返回零 (0),如果任何条件不满足,则返回一 (1)。在任何一种情况下,它也会输出有关其发现的文本。

以下示例来自手册页,有点复杂。它测试内核版本是否在 4.0 和 5.1 之间,主机是否在交流电源上运行,系统架构是否为 ARM 以外的任何架构,以及目录 /etc/os-release 是否存在。我添加了 echo $? 语句来打印返回代码。

[root@david ~]# systemd-analyze condition 'ConditionKernelVersion = ! <4.0' \
                    'ConditionKernelVersion = >=5.1' \
                    'ConditionACPower=|false' \
                    'ConditionArchitecture=|!arm' \
                    'AssertPathExists=/etc/os-release' ; \
echo $?
test.service: AssertPathExists=/etc/os-release succeeded.
Asserts succeeded.
test.service: ConditionArchitecture=|!arm succeeded.
test.service: ConditionACPower=|false failed.
test.service: ConditionKernelVersion=>=5.1 succeeded.
test.service: ConditionKernelVersion=!<4.0 succeeded.
Conditions succeeded.
0
[root@david ~]#

条件和断言的列表从 systemd.unit(5) 手册页上的第 600 行左右开始。

列出配置文件

systemd-analyze 工具提供了一种将各种配置文件的内容发送到 STDOUT 的方法,如下所示。基本目录是 /etc/

[root@david ~]# systemd-analyze cat-config systemd/system/display-manager.service
# /etc/systemd/system/display-manager.service
[Unit]
Description=LXDM (Lightweight X11 Display Manager)
#Documentation=man:lxdm(8)
Conflicts=getty@tty1.service
After=systemd-user-sessions.service getty@tty1.service plymouth-quit.service livesys-late.service
#Conflicts=plymouth-quit.service

[Service]
ExecStart=/usr/sbin/lxdm
Restart=always
IgnoreSIGPIPE=no
#BusName=org.freedesktop.lxdm

[Install]
Alias=display-manager.service
[root@david ~]#

这需要大量输入才能完成与标准 cat 命令相同的工作。我发现下一个命令稍微有用一点。它可以搜索标准 systemd 位置中具有指定模式的文件

[root@david ~]# systemctl cat backup*
# /etc/systemd/system/backup.timer
# This timer unit runs the local backup program
# (C) David Both
# Licensed under GPL V2
#

[Unit]
Description=Perform system backups
Requires=backup.service

[Timer]
Unit=backup.service
OnCalendar=*-*-* 00:15:30

[Install]
WantedBy=timers.target


# /etc/systemd/system/backup.service
# This service unit runs the rsbu backup program
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=Backup services using rsbu
Wants=backup.timer

[Service]
Type=oneshot
Environment="HOME=/root"
ExecStart=/usr/local/bin/rsbu -bvd1
ExecStart=/usr/local/bin/rsbu -buvd2

[Install]
WantedBy=multi-user.target

[root@david ~]#

这两个命令都在每个文件的内容前面加上一个注释行,其中包含文件的完整路径和名称。

单元文件验证

创建新的单元文件后,验证其语法是否正确可能很有帮助。这就是 verify 子命令的作用。它可以列出拼写错误的指令并调用缺少的服务单元

[root@david ~]# systemd-analyze verify /etc/systemd/system/backup.service

遵循 Unix/Linux “沉默是金”的理念,缺少输出消息意味着扫描的文件中没有错误。

安全性

security 子命令检查指定服务的安全级别。它仅适用于服务单元,而不适用于其他类型的单元文件

[root@david ~]# systemd-analyze security display-manager 
  NAME                                                        DESCRIPTION                                                     >
✗ PrivateNetwork=                                             Service has access to the host's network                        >
✗ User=/DynamicUser=                                          Service runs as root user                                       >
✗ CapabilityBoundingSet=~CAP_SET(UID|GID|PCAP)                Service may change UID/GID identities/capabilities              >
✗ CapabilityBoundingSet=~CAP_SYS_ADMIN                        Service has administrator privileges                            >
✗ CapabilityBoundingSet=~CAP_SYS_PTRACE                       Service has ptrace() debugging abilities                        >
✗ RestrictAddressFamilies=~AF_(INET|INET6)                    Service may allocate Internet sockets                           >
✗ RestrictNamespaces=~CLONE_NEWUSER                           Service may create user namespaces                              >
✗ RestrictAddressFamilies=~…                                  Service may allocate exotic sockets                             >
✗ CapabilityBoundingSet=~CAP_(CHOWN|FSETID|SETFCAP)           Service may change file ownership/access mode/capabilities unres>
✗ CapabilityBoundingSet=~CAP_(DAC_*|FOWNER|IPC_OWNER)         Service may override UNIX file/IPC permission checks            >
✗ CapabilityBoundingSet=~CAP_NET_ADMIN                        Service has network configuration privileges                    >
✗ CapabilityBoundingSet=~CAP_SYS_MODULE                       Service may load kernel modules
<SNIP>
✗ CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG                   Service may issue vhangup()                                     >
✗ CapabilityBoundingSet=~CAP_WAKE_ALARM                       Service may program timers that wake up the system              >
✗ RestrictAddressFamilies=~AF_UNIX                            Service may allocate local sockets                              >

→ Overall exposure level for backup.service: 9.6 UNSAFE ?
lines 34-81/81 (END)

是的,表情符号是输出的一部分。但是,当然,许多服务需要几乎完全访问所有内容才能完成其工作。我对多个服务(包括我自己的备份服务)运行了此程序;结果可能会有所不同,但底线似乎大致相同。

此工具对于检查和修复安全关键环境中的用户空间服务单元非常有用。我认为它对我们大多数人来说没有太多用处。

最终想法

这个强大的工具提供了一些有趣且非常有用的选项。本文探讨的大部分内容是关于使用 systemd-analyze 来深入了解使用 systemd 的 Linux 启动性能。它还可以分析 systemd 的其他方面。

其中一些工具用途有限,有些工具应该完全被遗忘。但是,大多数工具可以在解决启动和其他 systemd 功能的问题时发挥良好的作用。

资源

互联网上有大量关于 systemd 的信息,但其中许多信息简洁、晦涩甚至具有误导性。除了本文中提到的资源外,以下网页还提供了有关 systemd 启动的更详细和可靠的信息。自我开始撰写本系列文章以来,此列表已不断增长,以反映我所做的研究。

  • systemd.unit(5) 手册页包含单元文件部分的漂亮列表及其配置选项以及每个选项的简明描述。
  • Fedora 项目有一个很好的实用 systemd 指南。它几乎包含了您需要了解的所有内容,以便使用 systemd 配置、管理和维护 Fedora 计算机。
  • Fedora 项目还有一个很好的 速查表,将旧的 SystemV 命令交叉引用到可比较的 systemd 命令。
  • Red Hat 文档包含关于 单元文件结构 以及其他重要信息的良好描述。  
  • 有关 systemd 的详细技术信息以及创建它的原因,请查看 Freedesktop.org 的 systemd 描述
  • Linux.com 的“更多 systemd 乐趣”提供了更高级的 systemd 信息和技巧

Lennart Poettering(systemd 的设计者和主要开发人员)还为 Linux 系统管理员撰写了一系列深入的技术文章。这些文章写于 2010 年 4 月至 2011 年 9 月之间,但它们与现在一样具有现实意义。关于 systemd 及其生态系统的大部分其他优秀文章都基于这些论文。

接下来阅读什么
David Both
David Both 是一位开源软件和 GNU/Linux 倡导者、培训师、作家和演讲者。自 1996 年以来,他一直从事 Linux 和开源软件方面的工作,自 1969 年以来一直从事计算机方面的工作。他是“系统管理员的 Linux 哲学”的坚定支持者和传播者。

4 条评论

很棒的文章!这是非常有用的信息!

“mv systemd /bin/null ”
极大地简化了启动。 ;)

说真的,看看解释 systemd 需要多少篇文章。正如我们过去在工作中称之为“wonderful”——这是一个贬义词。

我用 Asus TUF B450m-plus 游戏主板组装了我的台式机。我遇到了与您的文章中描述的类似的 POST 失败问题。使用硬件排除过程,我发现 PCI 总线 NVMe 硬盘是根源。该驱动器是一个新的 silicon power 500G 2280 棒。我更换了它,POST 问题消失了。更换的是类似的 Crucial 驱动器。

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.