<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>
<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>
<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