<aside> 🧭

Module 08 · Execution Strategies & Performance at Scale

Making Ansible fast and safe on hundreds of hosts instead of five. Everything here is invisible on a three-host lab and decisive on a 500-host fleet.

🧠 concept → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (answers hidden)

Prerequisite: Modules 01–07. You met serial, forks and the task barrier in Module 03 — this module goes into the mechanics and the tuning.

</aside>


Part A · Where the time actually goes

A1 · The four costs

<aside> 🚗

The analogy. Think of a day of errands that took three hours when you expected one. The instinct is to blame the driving, and it is almost never the driving — it was twenty minutes hunting for parking at every stop, plus the fact that you visited them strictly one at a time instead of splitting the list between two cars.

"My playbook is slow" almost never means "my tasks are slow". It means SSH connection setup (the parking), fact gathering (a full check of the car at every stop), and only five hosts moving at once (one car). Those are the three things this module actually tunes, and the running of the modules themselves barely appears in the total.

</aside>

<aside> 📖

Official docs: Controlling playbook execution: strategies and more · Configuration settings · Callback plugins

</aside>

flowchart TD
    A["Total run time"] --> B["1 · SSH connection setup<br>one TCP + TLS handshake per host<br>FIX: ControlPersist multiplexing"]
    A --> C["2 · Fact gathering<br>a full extra module execution per host<br>FIX: gather_subset, caching, or off"]
    A --> D["3 · Per-task round trips<br>copy payload, execute, read JSON, delete<br>FIX: pipelining, fewer tasks, list arguments"]
    A --> E["4 · Serialisation<br>only 'forks' hosts progress at once<br>FIX: raise forks, or strategy: free"]
    style B fill:#FEF3C7,stroke:#D97706
    style C fill:#FEE2E2,stroke:#DC2626
    style D fill:#DDD6FE,stroke:#7C3AED
    style E fill:#D1FAE5,stroke:#059669

<aside> 🔑

The distribution most people get wrong. On a typical fleet run, fact gathering and connection setup dominate — not the tasks themselves. A playbook of 20 tasks against 200 hosts with forks: 5 spends far more time waiting on SSH and setup than doing work.

That is why the first three fixes are all about round trips, and why "my playbook is slow" almost never means "my tasks are slow".

</aside>

A2 · Measure before you tune

<aside> ⏱️

The analogy. Think of a doctor prescribing for a pain without examining you first. Treating the most common cause is a guess — sometimes it happens to work, and when it does not you have lost a week and learned nothing about what is actually wrong. The examination takes ten minutes and tells you where to look.

profile_tasks is the examination. It costs you nothing, and it prints exactly which task consumed the time. Raising forks before you have measured is prescribing before examining — and it is the single most common way people spend an afternoon tuning the wrong thing.

</aside>

# ansible.cfg
[defaults]
callbacks_enabled = profile_tasks, timer
ANSIBLE_CALLBACKS_ENABLED=profile_tasks,timer ansible-playbook site.yml
Callback What it reports
profile_tasks ⭐ Wall-clock per task, plus a slowest-tasks summary
timer Total playbook duration
profile_roles Time aggregated per role
cgroup_perf_recap CPU and memory used by the control node itself — for diagnosing fork limits

🧪 Exercise A2.1 — Find out where your time actually goes

ANSIBLE_CALLBACKS_ENABLED=profile_tasks,timer ansible-playbook site.yml 2>&1 | tail -25

🎯 Interview questions — Profiling