Ansible Forks optimieren: Gleichzeitigkeit und Ressourcenverbrauch ausbalancieren

Optimieren Sie Ansible Forks sicher, indem Sie Parallelität, Auslastung des Steuerungsknotens, Belastung der Zielknoten und Rollout-Risiko messen.

Ansible Forks optimieren: Gleichzeitigkeit und Ressourcenverbrauch ausbalancieren

Ansible's Stärke liegt in seiner agentenlosen Natur und der Fähigkeit, zahlreiche Hosts gleichzeitig zu verwalten. Diese Parallelität wird hauptsächlich durch die Einstellung forks gesteuert. Die richtige Abstimmung des Parameters forks ist entscheidend für einen optimalen Durchsatz Ihrer Automatisierungsaufgaben. Zu wenige Forks führen zu langsamen Playbooks; zu viele riskieren, Ihren Steuerungsknoten oder die verwalteten Knoten selbst zu überlasten.

Dieser Artikel dient als praktischer Leitfaden, um zu verstehen, was Ansible Forks sind, wie sie die Leistung beeinflussen und wie Sie den optimalen Wert für Ihre spezifische Umgebung ermitteln. Wir werden untersuchen, wo diese Einstellung definiert wird und welche Kompromisse mit aggressiver Parallelität verbunden sind.

Ansible Forks verstehen

In der Ansible-Terminologie repräsentiert ein Fork einen separaten Python-Prozess, der vom Ansible-Steuerungsknoten erzeugt wird, um eine Verbindung zu einem einzelnen verwalteten Host gleichzeitig zu verwalten. Wenn Sie ein Playbook ausführen, startet Ansible bis zu der durch forks definierten Anzahl von Prozessen, um Aufgaben parallel über Ihr Inventar auszuführen.

Warum Forks für die Leistung wichtig sind

Parallelität ist der Schlüssel zur Geschwindigkeit von Ansible. Wenn Sie 100 Server aktualisieren müssen, bedeutet die Einstellung forks = 100, dass Ansible versucht, sich zu genau demselben Zeitpunkt mit allen zu verbinden (vorbehaltlich Verbindungslimits und Timeouts). Diese Parallelität hat jedoch ihren Preis:

  1. Ressourcenverbrauch des Steuerungsknotens: Jeder Fork verbraucht CPU und Arbeitsspeicher auf dem Rechner, der Ansible ausführt (dem Steuerungsknoten). Hohe Fork-Anzahlen können den Steuerungsknoten aushungern, was zu träger Leistung, erhöhter Latenz und möglichen Abstürzen führt.
  2. Last auf den verwalteten Knoten: Schnelle Verbindungen können Netzwerk-Switches oder die verwalteten Hosts selbst überlasten, wenn diese bereits stark ausgelastet sind oder nur begrenzte CPU-Ressourcen haben, um eingehende SSH-Verbindungen und Aufgabenausführungen zu verarbeiten.

Wo der Parameter forks konfiguriert wird

Der Wert von forks kann an mehreren Stellen konfiguriert werden, wobei frühere Einstellungen in einer kaskadierenden Reihenfolge überschrieben werden. Das Verständnis dieser Hierarchie ist entscheidend für ein konsistentes Verhalten über verschiedene Projekte und Umgebungen hinweg.

1. Die Ansible-Konfigurationsdatei (ansible.cfg)

Der primäre, dauerhafte Ort für systemweite Standardeinstellungen ist die Datei ansible.cfg. Diese befindet sich typischerweise in /etc/ansible/ansible.cfg (systemweit) oder im Stammverzeichnis Ihres Projekts (projektspezifisch).

Um die Standard-Parallelitätsstufe festzulegen, ändern Sie den Abschnitt [defaults]:

# ansible.cfg Ausschnitt
[defaults]
# Legt die Standardanzahl paralleler Prozesse fest
forks = 50

2. Befehlszeilen-Override (-f oder --forks)

Sie können die Einstellung der Konfigurationsdatei temporär überschreiben, wenn Sie den Befehl ansible ausführen oder ein Playbook starten:

# Ein Playbook mit einer bestimmten Fork-Anzahl ausführen
ansible-playbook site.yml --forks 25

# Einen Ad-hoc-Befehl mit einer bestimmten Fork-Anzahl ausführen
ansible all -m ping -f 100

3. Umgebungsvariable

Für die skriptbasierte Ausführung oder CI/CD-Pipelines bietet die Einstellung der Umgebungsvariable ANSIBLE_FORKS eine flexible Möglichkeit, die Parallelität zu steuern, ohne Konfigurationsdateien zu ändern:

export ANSIBLE_FORKS=30
ansible-playbook site.yml

Konfigurationspriorität: Befehlszeilenargumente überschreiben Umgebungsvariablen, die wiederum die Einstellungen in ansible.cfg überschreiben.

So ermitteln Sie den optimalen Wert für forks

Die perfekte Anzahl von forks zu finden, ist ein iterativer Prozess, der auf empirischen Tests basiert. Es gibt keine einzelne magische Zahl; sie hängt stark von Ihrer Netzwerklatenz, der Kapazität des Steuerungsknotens und der Fähigkeit des Zielknotens ab.

Schritt 1: Kapazität des Steuerungsknotens bewerten

Bevor Sie mit der Optimierung beginnen, kennen Sie Ihre Einschränkungen. Ein dedizierter Steuerungsknoten mit freier CPU, Arbeitsspeicher und Netzwerkkapazität kann normalerweise mehr Forks verarbeiten als ein Laptop, der Ansible über ein VPN ausführt. Die genaue Anzahl hängt von der Arbeitslast, dem Verbindungs-Plugin, dem Python-Start-Overhead auf den verwalteten Hosts und der Datenmenge ab, die jede Aufgabe zurückgibt.

Bewährte Methode: Überwachen Sie die CPU- und Speichernutzung auf Ihrem Steuerungsknoten, während Sie ein mittelgroßes Playbook ausführen. Wenn die CPU-Auslastung konstant 100 % erreicht, bevor die Aufgabenausführung abgeschlossen ist, ist Ihre forks-Anzahl wahrscheinlich zu hoch für Ihre Hardware.

Schritt 2: Toleranz des Zielknotens bewerten

Wenn Ihre verwalteten Knoten kritische Dienste ausführen oder bereits stark ausgelastet sind, kann eine zu hohe Einstellung von forks zu Leistungseinbußen auf diesen Servern führen (z. B. langsame SSH-Antwort, unterbrochene Dienste).

Tipp: Wenn Sie nur nicht-invasive Aufgaben ausführen müssen (wie das Sammeln von Fakten), können Sie sich höhere Forks leisten. Wenn Sie große Anwendungsupdates bereitstellen, sollten Sie die Forks reduzieren, um die gleichzeitige Last auf Produktionssystemen zu minimieren.

Schritt 3: Empirischer Belastungstest

Beginnen Sie mit einem konservativen Wert (z. B. 20 oder 50) und erhöhen Sie ihn schrittweise, während Sie die Gesamtausführungszeit eines standardmäßigen, repräsentativen Playbooks messen.

Testiteration Forks-Einstellung Gesamtausführungszeit
1 20 450 Sekunden
2 50 210 Sekunden
3 100 185 Sekunden
4 150 190 Sekunden (Leichter Anstieg)

In diesem Beispiel-Lauf scheint der sinnvolle Balancepunkt bei etwa 100 Forks zu liegen, da eine Erhöhung auf 150 keine weitere Zeitersparnis brachte und wahrscheinlich unnötigen Overhead hinzufügte. Behandeln Sie dies als Testmuster, nicht als Benchmark. Ihr eigenes Ergebnis kann bei 20 Forks, 75 Forks oder einem ganz anderen Wert abflachen.

Interaktion mit Verbindungstypen

Die Einstellung forks arbeitet mit Ihrem gewählten Verbindungs-Plugin zusammen, am häufigsten ssh.

SSH-Verbindungslatenz

Wenn Ihre Verbindungslatenz hoch ist (z. B. über Kontinente oder langsame VPNs), stellen Sie möglicherweise abnehmende Erträge bei der Erhöhung der Forks fest, da die Zeit, die mit dem Warten auf den Verbindungsaufbau verbracht wird, die Ausführungszeit dominiert. In diesen Fällen kann die Reduzierung der Timeout-Einstellungen vorteilhafter sein als die Erhöhung der Forks.

Persistente Verbindungen (Async/ControlPersist)

In Umgebungen mit modernen SSH-Konfigurationen wie ControlPersist (das SSH-Sockets zwischen Ansible-Ausführungen offen hält) wird der Overhead des anfänglichen Verbindungsaufbaus amortisiert. Dies ermöglicht es Ihnen, sicher höhere Fork-Anzahlen zu verwenden, ohne durch die anfängliche Verbindungsaufbauzeit stark bestraft zu werden.

Vermeidung häufiger Fallstricke

forks zu hoch einzustellen, ist ein häufiger Leistungsfehler. Hier sind kritische Warnungen:

Warnung: Seien Sie vorsichtig, wenn Sie forks auf die Gesamtzahl der Hosts in einem großen Inventar setzen. In einem kleinen Labor kann das in Ordnung sein, aber in der Produktion sollte es zuerst getestet werden. Kombinieren Sie für große Inventare eine angemessene Fork-Anzahl mit serial, throttle, Batch-Verarbeitung oder separaten Inventargruppen, damit ein einzelner Playbook-Durchlauf keinen Verbindungssturm erzeugt.

Wenn Sie beim Erhöhen der Forks Fehler im Zusammenhang mit Cannot connect to host oder Connection timed out beobachten, ist dies ein starkes Indiz dafür, dass Sie die Kapazität entweder des Netzwerk-Stacks Ihres Steuerungsknotens oder der SSH-Daemon-Kapazität der verwalteten Knoten überschritten haben.

Ein praktischer Optimierungs-Walkthrough

Der einfachste Weg, Ansible Forks zu optimieren, ist die Verwendung eines Playbooks, das wie normale Arbeit in Ihrer Umgebung aussieht. Ein ping-Test ist nützlich, um die Konnektivität zu überprüfen, aber er ist zu leicht, um viel über den tatsächlichen Bereitstellungsdruck auszusagen. Ein besserer Test ist so etwas wie eine Paket-Metadaten-Aktualisierung, eine kleine Vorlagenbereitstellung, eine Dienststatusprüfung oder ein Trockenlauf der Rolle, die Sie am häufigsten ausführen.

Beginnen Sie damit, das aktuelle Verhalten aufzuzeichnen. Führen Sie das Playbook mit Ihrer vorhandenen Einstellung aus und speichern Sie die verstrichene Zeit, die Anzahl der fehlgeschlagenen Hosts und alles Ungewöhnliche vom Steuerungsknoten. Sie benötigen keinen komplexen Benchmark-Rahmen. time ansible-playbook -i inventory site.yml --limit web ist für einen ersten Durchgang oft ausreichend. Beobachten Sie in einem anderen Terminal den Steuerungsknoten mit top, htop, vm_stat, iostat oder was auch immer Ihr Betriebssystem bereitstellt. Wenn der Steuerungsknoten swapped, hilft eine Erhöhung der Forks nicht weiter.

Dann erhöhen Sie langsam. Wenn der aktuelle Wert 5 ist, versuchen Sie 10, 20 und 40. Wenn der aktuelle Wert 50 ist, versuchen Sie 75 und 100, bevor Sie auf mehrere hundert springen. Stellen Sie sich nach jedem Durchlauf drei Fragen:

  • Wurde das Playbook schneller fertig?
  • Traten Fehler oder Wiederholungen auf?
  • Wurden CPU, Arbeitsspeicher, Dateideskriptoren oder die Netzwerkauslastung unangenehm?

Der beste Wert liegt normalerweise kurz bevor die Kurve abflacht. Wenn 20 Forks 12 Minuten dauern, 50 Forks 6 Minuten und 100 Forks 5 Minuten 40 Sekunden, ist der zusätzliche Druck von 100 möglicherweise nicht wert. Ich würde in diesem Fall normalerweise 50 wählen, es sei denn, die gesparten Sekunden sind wichtig und die Umgebung wurde unter Last getestet.

Seien Sie besonders konservativ bei Plays, die Dienste neu starten, Datenbankmigrationen durchführen, Caches neu aufbauen oder gemeinsam genutzten Speicher berühren. Hohe Parallelität kann dazu führen, dass jeder Host gleichzeitig teure Arbeit verrichtet. Das mag genau das sein, was Sie für eine harmlose Dateiprüfung wollen, aber es kann ein schlechter Tag sein, wenn alle Anwendungsknoten gleichzeitig neu starten oder alle Datenbankreplikate gleichzeitig mit der Komprimierung von Dateien beginnen.

Achten Sie auch auf das Ausgabevolumen. Eine Aufgabe, die ein paar Zeilen von jedem Host zurückgibt, verhält sich anders als eine Aufgabe, die große Befehlsausgaben, Paketmanager-Protokolle oder JSON-Fakten von Hunderten von Maschinen streamt. Der Steuerungsknoten muss diese Daten sammeln, parsen und ausgeben. Wenn ein Durchlauf sich langsam anfühlt, obwohl die verwalteten Hosts im Leerlauf sind, versuchen Sie, laute Ausgaben zu reduzieren, nur das zu registrieren, was Sie benötigen, oder die Fakten-Sammlung einzuschränken, bevor Sie die Forks wieder erhöhen.

Es gibt auch eine menschliche Seite der Parallelität. Ein Playbook, das bei 3 von 20 Hosts fehlschlägt, ist leicht zu durchschauen. Ein Playbook, das bei 47 von 800 Hosts fehlschlägt, erzeugt einen langen Bericht, und der erste nützliche Fehler kann vergraben sein. Höhere Forks können den Durchlauf verkürzen, aber die Fehleranalyse überfüllter machen. Für operative Arbeiten bevorzuge ich eine Fork-Einstellung, die die Ausgabe lesbar hält, es sei denn, der Job ist vollständig automatisiert und verfügt bereits über eine gute Alarmierung bei Fehlern.

forks ist auch nicht die einzige Kontrolle, die Sie haben. Verwenden Sie serial, wenn Sie Hosts in Batches durchrollen möchten:

- name: Webanwendung sicher bereitstellen
  hosts: webservers
  serial: 10
  tasks:
    - name: Anwendungspaket aktualisieren
      ansible.builtin.package:
        name: myapp
        state: latest

Mit serial: 10 verarbeitet Ansible zehn Hosts gleichzeitig für dieses Play, selbst wenn forks viel höher ist. Das gibt Ihnen eine globale Parallelitätsobergrenze durch forks und eine Rollout-Strategie durch serial.

Verwenden Sie throttle, wenn eine Aufgabe empfindlicher ist als der Rest des Plays:

- name: API-Dienst in kleinen Gruppen neu starten
  ansible.builtin.service:
    name: api
    state: restarted
  throttle: 3

Das lässt frühere Aufgaben breit laufen, während die riskante Aufgabe eingeschränkt wird. Es ist eine sauberere Option, als forks für den gesamten Durchlauf zu senken, wenn nur ein Schritt Zurückhaltung benötigt.

Notieren Sie für CI-Systeme den gewählten Wert in der Projekt-ansible.cfg oder der Pipeline-Konfiguration. Versteckte lokale Einstellungen sind eine häufige Quelle von Verwirrung. Ein Entwickler läuft von einem Laptop mit forks = 5, ein anderer läuft von CI mit ANSIBLE_FORKS=100, und plötzlich verhält sich dasselbe Playbook ganz anders. Halten Sie den Standard langweilig und explizit und überschreiben Sie ihn nur für bekannte Fälle.

Ein Muster, das gut funktioniert, ist, einen konservativen Standard im Repository zu behalten:

[defaults]
forks = 25

Dann überschreiben Sie ihn für bekannte sichere Jobs:

ANSIBLE_FORKS=75 ansible-playbook -i inventory.ini facts-refresh.yml

Das macht die Ausnahme an der Aufrufstelle sichtbar. Eine Faktenaktualisierung über gesunde Hosts kann möglicherweise mehr Parallelität vertragen als ein rollierendes Deployment oder ein wartungsintensives Play mit Neustarts. Behandeln Sie forks als eine pro-Arbeitslast-Einstellung mit einem sinnvollen Standard, nicht als eine globale Zahl, die Sie einmal optimieren und dann vergessen.

Wenn Sie Ansible Automation Platform, AWX oder einen anderen Runner verwenden, denken Sie daran, dass es zusätzliche Parallelitätskontrollen außerhalb des Playbook-Prozesses geben kann. Job-Slicing, Instanzgruppenkapazität, Containerlimits und Ausführungsumgebungsressourcen können die Wirkung von forks begrenzen oder verstärken. Wenn ein Durchlauf Ihre Erwartung ignoriert, überprüfen Sie sowohl die Ansible-Einstellung als auch den Scheduler darum herum.