Bookmark this page

Configuring Parallelism

Objectives

  • Tune the number of simultaneous connections that Ansible opens to managed hosts and how Ansible processes groups of managed hosts through the play's tasks.

Configure Parallelism in Ansible Using Forks

When Ansible processes a playbook, it runs each play in order. After determining the list of hosts for the play, Ansible runs through each task in order. Normally, all hosts must successfully complete a task before any host starts the next task in the play.

In theory, Ansible could connect to all hosts in the play simultaneously for each task. This approach works fine for small lists of hosts, but if the play targets hundreds of hosts, it can put a heavy load on the control node and the automation execution environment.

The maximum number of simultaneous connections that Ansible makes is controlled by the forks parameter in the Ansible configuration file. This parameter is set to 5 by default, which you can verify by using one of the following methods:

[user@host demo]$ ansible-navigator config dump -m stdout
...output omitted...
DEFAULT_FORCE_HANDLERS(default) = False
DEFAULT_FORKS(default) = 5
DEFAULT_GATHERING(default) = implicit
...output omitted...
[user@host demo]$ ansible-navigator config list -m stdout
...output omitted...
DEFAULT_FORKS:
  default: 5
  description: Maximum number of forks Ansible will use to execute tasks on target
    hosts.
  env:
  - name: ANSIBLE_FORKS
  ini:
  - key: forks
    section: defaults
  name: Number of task forks
  type: integer
...output omitted...

Note

You can search the output of the previous two commands. To search for the default forks parameter type /DEFAULT_FORKS and press Enter.

For example, assume that Ansible is configured with the default value of five forks and that the play has ten managed hosts. Ansible runs the first task in the play on the first five managed hosts, followed by a second round of execution of the first task on the other five managed hosts. After running the first task on all the managed hosts, Ansible runs the next task across all the managed hosts in groups of five hosts at a time. Ansible does this with each task in turn until the play ends.

The default setting for forks is conservative. If a play that is running in your execution environment manages Linux hosts, most tasks run on the managed hosts, and the execution environment has less load. In this case, you can usually set the forks parameter to a much higher value, possibly closer to 100, and realize performance improvements.

If your plays run a lot of code in the execution environment, then you should raise the fork limit judiciously. If you use Ansible to manage network routers and switches, then most of those modules run in the execution environment and not on the network device. Because of the increased load this places on the execution environment, the number of forks should be significantly lower compared to a play running in an execution environment that manages only Linux hosts.

You can override the default setting for the forks option from the command line by modifying the Ansible configuration file. The ansible-navigator run command offers the -f or --forks option to specify the number of forks.

Running Batches of Hosts Through the Entire Play

Normally, when Ansible runs a play, it ensures that all managed hosts complete each task before it starts the next task. After all managed hosts have completed all tasks, then any notified handlers are run.

However, running all tasks on all hosts can lead to undesirable behavior. For example, if a play updates a cluster of load-balanced web servers, it might need to take each web server out of service during the update. If all the servers are updated in the same play, they could all be out of service simultaneously.

One way to avoid this problem is to use the serial keyword to run the hosts through the play in batches. The play processes each batch of hosts in sequence.

In the example below, Ansible runs the play on two managed hosts simultaneously until all managed hosts have been updated. Ansible first runs the tasks in the play on the first two managed hosts. If any of those hosts notifies a handler, then Ansible runs the handler. When the play is complete on those two managed hosts, Ansible repeats the process on the next two managed hosts. Ansible continues to run the play in this way until all managed hosts are updated.

---
- name: Rolling update
  hosts: webservers
  serial: 2
  tasks:
    - name: Latest apache httpd package is installed
      ansible.builtin.yum:
        name: httpd
        state: latest
      notify: restart apache

  handlers:
    - name: Restart apache
      ansible.builtin.service:
        name: httpd
        state: restarted

Suppose that the webservers group in the previous example contains five web servers behind a load balancer. With the serial parameter set to 2, the play runs on up to two web servers simultaneously. Thus, a majority of the five web servers is always available.

In contrast, in the absence of the serial keyword, the play and resulting handler would run across all five web servers at the same time. This approach would probably lead to a service outage because web services on all the web servers would be restarted at the same time.

Important

For certain purposes, each batch of hosts counts as if it was a full play running on a subset of hosts. This means that if an entire batch fails, then the play fails, which causes the entire playbook run to fail.

In the previous scenario with the serial parameter set to 2, if something is wrong and the play fails for the first two processed hosts, then the playbook aborts and the play does not run on the remaining three hosts. This is a useful feature because only a subset of the servers would be unavailable, leaving the service degraded rather than down.

The serial keyword can also be specified as a percentage. This percentage is applied to the total number of hosts in the play to determine the rolling update batch size. Regardless of the percentage, the number of hosts per pass is always one or greater.

Revision: do374-2.2-82dc0d7