Linux-Bootzeit beschleunigen: Systemd-Unit-Abhängigkeiten analysieren und optimieren

Nutzen Sie systemd-analyze, critical-chain und die Bereinigung von Unit-Abhängigkeiten, um langsame Linux-Boot-Pfade zu finden und zu beheben.

Linux-Bootzeit beschleunigen: Systemd-Unit-Abhängigkeiten analysieren und optimieren

Die Optimierung der Linux-Bootzeit beginnt mit einer Frage: Was blockiert tatsächlich, dass Ihr System nutzbar wird? Bei den meisten modernen Distributionen startet systemd Dienste parallel, aber eine langsame Unit oder eine unnötige Reihenfolgeregelung kann den Boot-Pfad dennoch aufhalten.

Indem Sie überprüfen, welche Units Zeit benötigen und welche Units sich in der kritischen Kette befinden, können Sie entscheiden, ob Sie sie anpassen, verzögern oder deaktivieren möchten. Die folgenden Beispiele konzentrieren sich auf systemd-analyze und kleine Abhängigkeitsänderungen, die Ihr System vorhersagbar halten.

Den Systemd-Boot-Prozess verstehen

Systemd verwaltet den Startprozess, indem es Dienste wann immer möglich parallel ausführt. Ein Dienst kann jedoch nur starten, wenn alle seine expliziten und impliziten Abhängigkeiten erfüllt sind. Wenn Unit A erfordert, dass Unit B vollständig aktiv ist, bevor sie fortfahren kann, wird Unit A von Unit B blockiert. Das Identifizieren dieser blockierenden Abhängigkeiten ist der erste Schritt zur Beschleunigung.

Wichtige Systemd-Analysewerkzeuge

Systemd bietet mehrere leistungsstarke Befehlszeilenprogramme zur Diagnose der Boot-Leistung. Die folgenden Werkzeuge sind unerlässlich, um Engpässe zu lokalisieren:

1. systemd-analyze (Gesamtansicht)

Dieser Befehl bietet einen allgemeinen Überblick über die Gesamtzeit, die für den Kernel, die Userspace-Initialisierung und die Zeit zum Laden verfügbarer Ziele benötigt wird.

systemd-analyze

Beispiel für die Ausgabeinterpretation:

Komponente Benötigte Zeit
Kernel 1.234s
Initrd 0.500s
Userspace 5.789s
Gesamt 7.523s

Dies zeigt Ihnen schnell, ob der Engpass in der Kernel-Phase (Firmware-/Treiberladung) oder der Userspace-Phase (Dienststart) liegt.

2. systemd-analyze blame (Langsame Units identifizieren)

Dieser Befehl listet Units sortiert nach der Zeit, die sie für die Aktivierung benötigt haben, mit den längsten Zeiten oben.

systemd-analyze blame

Fokus: Betrachten Sie die ersten 10 Einträge. Dies sind die Dienste, die während des Starts aktiv Zeit verbrauchen. Beachten Sie, dass eine lange Initialisierungszeit einfach bedeuten kann, dass der Dienst viel Arbeit leistet; das Ziel ist zu sehen, ob diese Arbeit während des Bootvorgangs erledigt werden muss.

3. systemd-analyze critical-chain (Abhängigkeitsanalyse)

Dieser Befehl zeigt die Abhängigkeitskette, die zum Boot-Ziel (normalerweise graphical.target oder multi-user.target) führt. Er hebt die Sequenz von Units hervor, die abgeschlossen sein müssen, bevor das System als vollständig gebootet gilt.

systemd-analyze critical-chain

Units, die in der kritischen Kette aufgeführt sind, sind primäre Ziele für die Optimierung, da ihre Verzögerung den gesamten Systemstart verzögert.

4. systemd-analyze plot (Boot-Sequenz visualisieren)

Für eine grafische Darstellung von Parallelität und Blockierung verwenden Sie den Plot-Befehl, der eine SVG-Datei erzeugt:

systemd-analyze plot > boot_analysis.svg
# Öffnen Sie boot_analysis.svg in einem Webbrowser

Diese Grafik zeigt visuell, welche Dienste parallel laufen und welche auf andere warten, wodurch Abhängigkeitsprobleme sofort erkennbar werden.

Optimierungstechniken: Unit-Dateien ändern

Sobald Sie mit den obigen Werkzeugen langsame oder blockierende Units identifiziert haben, besteht die Optimierung darin, entweder die Unit selbst zu beschleunigen oder zu ändern, wann sie ausgeführt werden muss.

1. Langsame Units adressieren, die durch blame identifiziert wurden

Wenn ein Dienst, der in der blame-Ausgabe weit oben steht (z. B. slow-database.service benötigt 10 Sekunden), nicht sofort für den grundlegenden Systembetrieb (wie Anmelden oder grundlegende Netzwerkfunktionen) erforderlich ist, sollten Sie ihn verzögern.

Aktion: Ändern Sie seine Startabhängigkeitsstufe.

  • Wenn er derzeit bei multi-user.target startet, prüfen Sie, ob er stattdessen von einem Timer, Socket, Pfad-Unit oder manuellen Befehl gestartet werden kann.
  • Wenn der Dienst optional ist, ist das Deaktivieren normalerweise sicherer, als das Kernabhängigkeitsverhalten zu ändern. Verwenden Sie DefaultDependencies=no nur, wenn Sie die Standard-Reihenfolge verstehen, die systemd normalerweise für diesen Unit-Typ hinzufügen würde.

2. Abhängigkeiten mit Wants, Requires und After optimieren

Unit-Dateien steuern die Ausführungsreihenfolge mithilfe von Abhängigkeitsdirektiven. Fehlkonfigurationen hier sind eine häufige Quelle unnötiger sequenzieller Ausführung.

Abhängigkeitstypen:

  • Requires=: Eine starke Abhängigkeit. Wenn die erforderliche Unit fehlschlägt, schlägt auch diese Unit fehl.
  • Wants=: Eine schwache Abhängigkeit. Diese Unit startet, wenn die gewünschte Unit verfügbar ist, wird aber trotzdem versuchen zu starten, wenn die gewünschte Unit fehlschlägt.
  • After=: Reihenfolgedirektive. Diese Unit startet erst nachdem die angegebene Unit den Start abgeschlossen hat (unabhängig vom Erfolg).
  • Before=: Reihenfolgedirektive. Diese Unit muss vor der angegebenen Unit starten.

Best-Practice-Tipp: Bevorzugen Sie Wants gegenüber Requires für optionale Beziehungen. Wants= ändert das Fehlerverhalten, nicht die Reihenfolge an sich. Eine gewünschte Unit kann trotzdem parallel starten, es sei denn, Sie fügen auch eine Reihenfolgeregel wie After= hinzu.

Entfernen unnötiger After=-Einschränkungen

Der effektivste Weg, die Bootzeit zu verkürzen, ist die Beseitigung unnötiger Reihenfolgeeinschränkungen. Wenn Unit A funktional nicht darauf angewiesen ist, dass Unit B gestartet ist, bevor Unit A beginnt, entfernen Sie die Zeile After=unit-b.service aus der Definition von Unit A.

Beispieländerung (Konzeptionell):

Angenommen, Ihre benutzerdefinierte Anwendungs-Unit app.service wartet unnötigerweise auf den Netzwerkkonfigurationsdienst:

# /etc/systemd/system/app.service
[Unit]
Description=Meine Anwendung
Requires=network.target
After=network.target  <-- Potenziell unnötiges Warten!

[Service]
ExecStart=/usr/bin/myapp

Wenn Ihre Anwendung nur ein lokales Loopback-Interface benötigt oder nur eine lokale Dateisperre einrichten muss, kann das Warten auf den vollständigen Netzwerk-Stack (network.target) mehrere Sekunden verschwenden. Wenn Sie bestätigen, dass die Anwendung das externe Netzwerk nicht wirklich benötigt, entfernen Sie die Zeile After=network.target. Systemd wird dann versuchen, app.service so früh wie möglich parallel zur Netzwerkeinrichtung zu starten.

3. Nicht benötigte Dienste maskieren

Wenn systemd-analyze blame einen Dienst zeigt, den Sie absolut nicht benötigen (z. B. unnötige Bluetooth-Unterstützung auf einem Server oder ein bestimmter Hardware-Monitor), verhindert das Deaktivieren oder Maskieren, dass er überhaupt startet.

  • Deaktivieren: systemctl disable <unit> (Verhindert den Start bei zukünftigen Bootvorgängen).
  • Maskieren (Stärker): systemctl mask <unit> (Verknüpft die Unit mit /dev/null und verhindert auch manuelle Startversuche).
# Beispiel: Maskieren des ModemManager, wenn kein Mobilfunkmodem vorhanden ist
sudo systemctl mask ModemManager.service

Änderungen neu laden und überprüfen

Nachdem Sie eine Unit-Datei geändert haben (insbesondere solche, die in /etc/systemd/system/ abgelegt sind), müssen Sie systemd anweisen, seine Konfiguration neu zu laden, bevor Sie zum Testen neu starten:

sudo systemctl daemon-reload

# Überprüfen Sie dann vor dem Neustart Abhängigkeiten oder Status
systemctl list-dependencies myapp.service

Starten Sie schließlich immer das System neu, um die tatsächlichen Auswirkungen auf die Boot-Sequenz zu messen.

sudo reboot

Führen Sie nach dem Neustart sofort erneut systemd-analyze aus, um die durch Ihre Optimierungen erzielten Zeitersparnisse zu quantifizieren.

Fazit

Behandeln Sie die Boot-Optimierung als eine kleine Änderungsschleife: Messen Sie mit systemd-analyze, finden Sie die Units im kritischen Pfad, entfernen Sie nur die Reihenfolgeregeln, die Sie rechtfertigen können, starten Sie dann neu und messen Sie erneut. Die sichersten Erfolge erzielen Sie normalerweise durch das Deaktivieren unnötiger Dienste, das Umwandeln von Arbeiten in Timer oder Socket-Aktivierung und das Entfernen unnötiger After=-Zeilen aus Ihren eigenen Units.