当前位置:网站首页>Ansible 学习总结(11)—— task 并行执行之 forks 与 serial 参数详解
Ansible 学习总结(11)—— task 并行执行之 forks 与 serial 参数详解
2022-08-02 07:45:00 【科技D人生】
前言
Ansible 执行 task 的时候,会依据配置文件中指定的 forks 参数、inventory 中指定的主机以及主机组、以及选择的目标主机和定义的 task 数决定执行的方式。比如 inventory 主机清单文件中,记录了 20 台服务器,配置文件中的 forks 参数指定为 5,同时有 2 个 task 需要执行,此时就表示每次最多允许对 5 台服务器进行操作,如果剩下的服务器数不足 5 台,则对剩下的所有服务器执行操作。那么对于多个 task 以及多台服务器执行的时候,按照目标主机的执行方式,通常有两种方式:
- 广度优先:将每个 task 先按照 forks 约定的参数,在所有服务器上分批并行执行,等这个 task 执行完毕之后,继续按照相同的方式执行后续的 task。
- 深度优先:serial 指定(通常小于 forks 指定的参数)约定数目的服务器上并行执行完所有的 task 之后继续在下一组服务器上,按照相同的方式执行完所有的 task。
一、forks(广度优先)
依据 forks 参数,决定一次在多少个服务器上并行执行相应的 task,对于包含多个 task 的场景,这种方式会先将 1 个 task 在指定的所有服务器上都执行完成之后,才会执行后续的 task。所以对于一个包含多个 task 的 playbook 来说,此时所有服务器的状态都是不完整的,都是处于中间状态的。但是当这个包含多个 task 的 playbook 执行完成之后,所有执行成功的服务器的状态都是被更新完成的。这种方式适合对服务器的中间状态不敏感的场景,其优点是可以对指定的所有主机执行同步的配置操作;缺点是更新过程中所有服务器都是未完成配置的中间状态。比如下面的场景,有 4 台服务器需要配置(nodeA, nodeB, nodeC, nodeD),playbook 中定义了 2 个 task,forks 指定的参数是 5,而每个 task 执行的耗时为 5 秒。此时,执行过程如下:
- 第一次执行:由于 forks 数大于服务器数,所以所有的服务器都会被选中,并行执行第一个 task,所以此时执行完成耗时为 5 秒;
- 第二次执行:同样所有的服务器都会被选中,并且并行执行第二个 task,所以此时执行完成耗时同样为 5 秒。
- 最终,这个 playbook 在所有服务器上执行完成之后,总的耗时为 10 秒。
示例代码如下:
[email protected]:1st$ vim test_forks.yml
[email protected]:1st$ cat test_forks.yml
---
- hosts: c7u6s1,c7u6s2,c7u6s3,c7u6s4
gather_facts: false
tasks:
- name: echo hostname
command: hostname
- name: echo datetime
command: date
[email protected]:1st$ ansible-playbook -f 5 test_forks.yml
PLAY [c7u6s1,c7u6s2,c7u6s3,c7u6s4] >******************************************************************************************> ******************
TASK [echo hostname] **************************************************************************************************************************
changed: [c7u6s1]
changed: [c7u6s2]
changed: [c7u6s3]
changed: [c7u6s4]
TASK [echo datetime] >**************************************************************************************************************************
changed: [c7u6s1]
changed: [c7u6s3]
changed: [c7u6s2]
changed: [c7u6s4]
PLAY RECAP ************************************************************************************************************************************
c7u6s1 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s2 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s3 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s4 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[email protected]:1st$ 上述输出结果中,显示每个 task 在所有服务器上并行执行,执行完成之后,才会开始执行后续的 task。上面是 forks 数大于服务器数的情况,对于 forks 数小于服务器数的场景,比如有 4 台服务器,playbook 中同样有 2 个task,forks 数配置为 2,每个 task 的执行所需时间仍然为 5 秒。此时的执行过程如下:
- 第一次执行:4台服务器中的2台被选中,并行执行第一个task,所以执行完成之后的耗时为5秒;
- 第二次执行:剩下的2台服务器被选中,执行第一个task,所以此时执行完成之后耗时5秒;
- 第三次执行:4台服务器中的2台被选中,并行执行第二个task,所以执行完成之后耗时为5秒;
- 第四次执行:剩下的2台服务器被选中,执行第二个task,所以执行完成耗时为5秒;
- 最终总的耗时为20秒。
示例代码如下:
---
- hosts: c7u6s1,c7u6s2,c7u6s3,c7u6s4
gather_facts: false
tasks:
- name: echo hostname
shell: hostname; sleep 1
- name: echo datetime
shell: date; sleep 1执行上述的 palybook,具体如下:
[email protected]:1st$ ansible-playbook -f 2 -v test_forks.yml
Using /etc/ansible/ansible.cfg as config file
PLAY [c7u6s1,c7u6s2,c7u6s3,c7u6s4] ************************************************************************************************************
TASK [echo hostname] **************************************************************************************************************************
changed: [c7u6s1] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "hostname; sleep 1", "delta": "0:00:01.006387", "end": "2022-06-28 17:10:30.556334", "msg": "", "rc": 0, "start": "2022-06-28 17:10:29.549947", "stderr": "", "stderr_lines": [], "stdout": "c7u6s1", "stdout_lines": ["c7u6s1"]}
changed: [c7u6s2] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "hostname; sleep 1", "delta": "0:00:01.003715", "end": "2022-06-28 17:10:30.557691", "msg": "", "rc": 0, "start": "2022-06-28 17:10:29.553976", "stderr": "", "stderr_lines": [], "stdout": "c7u6s2", "stdout_lines": ["c7u6s2"]}
changed: [c7u6s3] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "hostname; sleep 1", "delta": "0:00:01.004623", "end": "2022-06-28 17:10:31.800163", "msg": "", "rc": 0, "start": "2022-06-28 17:10:30.795540", "stderr": "", "stderr_lines": [], "stdout": "c7u6s3", "stdout_lines": ["c7u6s3"]}
changed: [c7u6s4] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "hostname; sleep 1", "delta": "0:00:01.004561", "end": "2022-06-28 17:10:31.811011", "msg": "", "rc": 0, "start": "2022-06-28 17:10:30.806450", "stderr": "", "stderr_lines": [], "stdout": "c7u6s4", "stdout_lines": ["c7u6s4"]}
TASK [echo datetime] **************************************************************************************************************************
changed: [c7u6s1] => {"changed": true, "cmd": "date; sleep 1", "delta": "0:00:01.005884", "end": "2022-06-28 17:10:33.050719", "msg": "", "rc": 0, "start": "2022-06-28 17:10:32.044835", "stderr": "", "stderr_lines": [], "stdout": "Tue Jun 28 17:10:32 CST 2022", "stdout_lines": ["Tue Jun 28 17:10:32 CST 2022"]}
changed: [c7u6s2] => {"changed": true, "cmd": "date; sleep 1", "delta": "0:00:01.004152", "end": "2022-06-28 17:10:33.051957", "msg": "", "rc": 0, "start": "2022-06-28 17:10:32.047805", "stderr": "", "stderr_lines": [], "stdout": "Tue Jun 28 17:10:32 CST 2022", "stdout_lines": ["Tue Jun 28 17:10:32 CST 2022"]}
changed: [c7u6s3] => {"changed": true, "cmd": "date; sleep 1", "delta": "0:00:01.004385", "end": "2022-06-28 17:10:34.231918", "msg": "", "rc": 0, "start": "2022-06-28 17:10:33.227533", "stderr": "", "stderr_lines": [], "stdout": "Tue Jun 28 17:10:33 CST 2022", "stdout_lines": ["Tue Jun 28 17:10:33 CST 2022"]}
changed: [c7u6s4] => {"changed": true, "cmd": "date; sleep 1", "delta": "0:00:01.004384", "end": "2022-06-28 17:10:34.236657", "msg": "", "rc": 0, "start": "2022-06-28 17:10:33.232273", "stderr": "", "stderr_lines": [], "stdout": "Tue Jun 28 17:10:33 CST 2022", "stdout_lines": ["Tue Jun 28 17:10:33 CST 2022"]}从上述的输出时间中,可以看出,每个 task 都是分 2 次执行的,因为指定了 forks 数为 2,实际主机数为 4 台。上述就是所谓的广度优先,即先在所有主机上执行 1 个 task,直至所有的主机都执行完成之后,采用相同的方式执行后续的 task。
三、serial(深度优先)
而对于深度优先的执行方式,则是在指定数目的服务器上执行完 playbook 的所有 task 之后,才会继续在剩余的其他主机上执行这个 playbook 中定义的 task。这是通过在 playbook 中指定 serial 关键字实现的,所以其是在 forks 参数的基础上,进一步进行约定,从而实现指定数目的服务器执行完成 playbook 之后,才会在其他服务器上执行的操作。这种方式类似于滚动更新。比如,此时仍然为 4 台服务器,forks 仍然设置为 5,然后在 playbook 中增加 serial 关键字,并将其值设置为 2,playbook 中仍然有 2 个 task,且每个 task 执行耗费时间为5秒。此时的执行过程如下:
- 第一次执行:从4台服务器中挑选两台,并行执行第一个task,直至第一个task执行完成,此时耗费时间为5秒;
- 第二次执行:在这两台服务器上,继续并行执行第二个task,直至第二个task执行完成,此时耗费时间为5秒;
- 第三次执行:在剩下的2台服务器上,并行执行第一个task,直至第一个task执行完成,此时耗费时间为5秒;
- 第四次执行:继续在剩下的2台服务器上,并行执行第二个task,直至diergetask执行完成,此时耗时为5秒;
- 至此,4台服务器上都已经执行完成了,总耗时为20秒。
示例代码如下:
---
- hosts: c7u6s1,c7u6s2,c7u6s3,c7u6s4
gather_facts: false
serial: 2
tasks:
- name: echo hostname
shell: hostname; sleep 1
- name: echo datetime
shell: date; sleep 1执行过程如下:
[email protected]:1st$ ansible-playbook -f 5 test_serial.yml
PLAY [c7u6s1,c7u6s2,c7u6s3,c7u6s4] ************************************************************************************************************
TASK [echo hostname] **************************************************************************************************************************
changed: [c7u6s2]
changed: [c7u6s1]
TASK [echo datetime] **************************************************************************************************************************
changed: [c7u6s1]
changed: [c7u6s2]
PLAY [c7u6s1,c7u6s2,c7u6s3,c7u6s4] ************************************************************************************************************
TASK [echo hostname] **************************************************************************************************************************
changed: [c7u6s3]
changed: [c7u6s4]
TASK [echo datetime] **************************************************************************************************************************
changed: [c7u6s3]
changed: [c7u6s4]
PLAY RECAP ************************************************************************************************************************************
c7u6s1 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s2 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s3 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s4 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[email protected]:1st$上述输出结果,也验证了执行过程,即在 serial 指定数目的服务器上执行完 playbook 中定义的所有 task 之后,才会继续在后续的其他服务器上执行这个 playbook。如果 playbook 中的 serial 值比 forks 的值大,此时以 serial 为准,执行并行操作。修改后的 yaml 文件具体如下所示:
---
- hosts: c7u6s1,c7u6s2,c7u6s3,c7u6s4
gather_facts: false
serial: 4
tasks:
- name: echo hostname
shell: hostname; sleep 1
- name: echo datetime
shell: date; sleep 1执行上述 playbook 的时候,指定 forks 值为 2,此时 serial 的值比 forks 值大。此时的执行效果如下:
[email protected]:1st$ ansible-playbook -f 2 test_serial.yml
PLAY [c7u6s1,c7u6s2,c7u6s3,c7u6s4] ************************************************************************************************************
TASK [echo hostname] **************************************************************************************************************************
changed: [c7u6s1]
changed: [c7u6s2]
changed: [c7u6s3]
changed: [c7u6s4]
TASK [echo datetime] **************************************************************************************************************************
changed: [c7u6s1]
changed: [c7u6s2]
changed: [c7u6s3]
changed: [c7u6s4]
PLAY RECAP ************************************************************************************************************************************
c7u6s1 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s2 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s3 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s4 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0可以看出,上述的执行过程,是 4 个服务器并行执行,并行数量并不受 forks 的数量限制。从上述的两种方式中可以看出,forks 和 serial 都可以决定并行执行的服务器数量,当没有在 playbook 中指定 serial 的时候,则以 forks 的值作为并行运行的服务器数量依据;当在 playbook 中指定了 serial 且同时配置了 forks 的时候,则以 serial 的值作为并行运行的服务器数量的依据。
serial 的其他用法
serial关 键字除了可以指定为数字之外,还可以指定为百分数,表示单次并行执行的主机数占指定的总主机数的百分比。此时的定义形式如下:
---
- name: test play
hosts: webservers
serial: "30%"
tasks:
- name: task1
command: hostname
- name: task2
command: datetime上述输出表示,每次从指定的所有主机中选择 30% 执行。还可以将 serial 的值设置为列表,每个列表项表示并行执行的服务器数量。具体如下:
---
- name: test play
hosts: webservers
serial:
- 1
- 5
- 10
tasks:
- name: task1
command: hostname
- name: task2
command: date上述代码的含义,是第一次执行的时候,从指定的所有服务器中挑选 1 台,执行 playbook 中的所有 task,第二次执行的时候,从指定的所有服务器中选中 5 台执行 playbook 中的所有 task,第三次执行,从指定的所有服务器中选中 10 台执行 playbook 中的所有 task,此时如果还有未执行过的服务器,则按照 forks 定义的数量并行执行。在 serial 的列表中,还可以将数字与百分数混合使用,具体如下:
---
- name: test play
hosts: webservers
serial:
- 1
- "50%"
tasks:
- name: task1
command: hostname
- name: task2
command: date上述代码的含义,是从指定的服务器中选择 1 台执行 playbook,当执行完成之后,从剩余主机中选择全部主机总数的 50% 的主机执行 playbook,此时如果还有未执行过的指定主机,则按照 forks 的指定参数,并行执行。代码如下:
---
- hosts: c7u6s1,c7u6s2,c7u6s3,c7u6s4
gather_facts: false
serial:
- 1
- 50%
tasks:
- name: echo hostname
shell: hostname; sleep 1
- name: echo datetime
shell: date; sleep 1上述 playbook 的执行过程如下:
[email protected]:1st$ ansible-playbook -f 5 test_serial.yml
PLAY [c7u6s1,c7u6s2,c7u6s3,c7u6s4] ************************************************************************************************************
TASK [echo hostname] **************************************************************************************************************************
changed: [c7u6s1]
TASK [echo datetime] **************************************************************************************************************************
changed: [c7u6s1]
PLAY [c7u6s1,c7u6s2,c7u6s3,c7u6s4] ************************************************************************************************************
TASK [echo hostname] **************************************************************************************************************************
changed: [c7u6s2]
changed: [c7u6s3]
TASK [echo datetime] **************************************************************************************************************************
changed: [c7u6s3]
changed: [c7u6s2]
PLAY [c7u6s1,c7u6s2,c7u6s3,c7u6s4] ************************************************************************************************************
TASK [echo hostname] **************************************************************************************************************************
changed: [c7u6s4]
TASK [echo datetime] **************************************************************************************************************************
changed: [c7u6s4]
PLAY RECAP ************************************************************************************************************************************
c7u6s1 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s2 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s3 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
c7u6s4 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0从上述输出中可以看出,先挑选出一台服务器执行 playbook,执行完成之后,从剩余的服务器中选择总数的 50% 的服务器(总数 4 台,50% 即为 2 台)继续执行 playbook,此时还有主机没有被执行完,且此时的 forks 数大于剩余的服务器数,所以直接将剩余的服务器全部执行。
边栏推荐
猜你喜欢

Visual Analysis of DeadLock

redis-advanced

redis的安装与应用

PanGu-Coder:函数级的代码生成模型

Understand Chisel language. 31. Chisel advanced communication state machine (3) - Ready-Valid interface: definition, timing and implementation in Chisel

如何开启mysql慢查询日志?

MySQL压缩包方式安装,傻瓜式教学

Biotin hydrazide HCl|CAS:66640-86-6|生物素-酰肼盐酸盐

设置工作模式与环境(中):建造二级引导器

Inverter insulation detection detection function and software implementation
随机推荐
Introduction to Totem Pole and Push-Pull Circuits
理论问题与工程问题的差异在哪里?
读入、输出优化
Inverter insulation detection detection function and software implementation
小说里的编程 【连载之二十三】元宇宙里月亮弯弯
2022-2023 十大应用开发趋势
sql创建表格 如图 运行完提示invalid table name 是什么原因
【Unity3D】初学加密技巧(反破解)
MySQL-Execution Process + Cache + Storage Engine
【Network】IP, subnet mask
postgres 水平分表,自动创建分区,按时间分表
MySQL - based
2022-08-01 第四小组 修身课 学习笔记(every day)
DeadLock的可视化分析
Postgres horizontal table, automatically create partitions, table by time
Inverter Phase Locking Principle and DSP Implementation
传递泛型给JSX元素
数据表格化打印输出
研发过程中的文档管理与工具
Kind of weird!Access the destination URL, the host can container but not