如何加速Ansible中uri模块的loop循环任务?
加速Ansible循环中Web请求的实用方案
首先得说清楚为什么你之前的异步方案反而变慢了——你用poll:0让任务后台跑,然后逐个循环等待每个任务完成,这种方式根本没发挥并行的优势,反而增加了Ansible管理异步任务的额外开销(比如每个任务的状态查询、jid记录),串行等待的逻辑甚至比直接串行执行请求更耗时。
下面给你几个实际可行的优化方向,按效果优先级排序:
1. 优先尝试批量请求(效果最显著)
如果Nagios XI的API支持批量创建服务(大部分新版本都支持),直接把所有要提交的服务数据打包成一个请求发送,这能把N次请求压缩成1次,速度提升是数量级的。
先把所有挂载点的服务参数预整理好,再调用批量API:
- name: 整理批量提交的Nagios服务数据 set_fact: nagios_batch_services: "{{ nagios_batch_services | default([]) + [service_data] }}" loop: "{{ ansible_mounts }}" vars: warning: "{{ fs[ansible_fqdn][item.mount]['warning'] if ((fs is defined) and ansible_fqdn in fs and item.mount in fs[ansible_fqdn] and 'warning' in fs[ansible_fqdn][item.mount]) else fs['defaults']['warning']}}" critical: "{{ fs[ansible_fqdn][item.mount]['critical'] if ((fs is defined) and ansible_fqdn in fs and item.mount in fs[ansible_fqdn] and 'critical' in fs[ansible_fqdn][item.mount]) else fs['defaults']['critical']}}" service_data: host_name: "{{ ansible_fqdn }}" service_description: "FS {{ item.mount }}" register: 1 check_command: "check_nrpe!check_fs_single!\'-w {{ warning }} -c {{ critical }} -p {{ item.mount }} -e -l -u {{ 'MB' if item.size_total is defined and item.size_total < 5368709120 else 'GB' }}\'-!!!!!!" initial_state: "{{ fs[ansible_fqdn][item.mount]['initial_state'] if ((fs is defined) and ansible_fqdn in fs and item.mount in fs[ansible_fqdn] and 'initial_state' in fs[ansible_fqdn][item.mount]) else service[env]['initial_state']}}" max_check_attempts: "{{ fs[ansible_fqdn][item.mount]['max_check_attempts'] if ((fs is defined) and ansible_fqdn in fs and item.mount in fs[ansible_fqdn] and 'max_check_attempts' in fs[ansible_fqdn][item.mount]) else service[env]['max_check_attempts']}}" # 把原任务中所有body参数都复制到这里 when: item.fstype == 'xfs' or item.fstype == 'ext4' - name: 批量推送服务到Nagios delegate_to: localhost uri: url: "https://nagios/nagiosxi/api/v1/config/services?apikey={{ nagios_apikey }}" method: POST body_format: json body: "{{ nagios_batch_services }}" register: batch_upload failed_when: 'batch_upload.json is defined and batch_upload.json.error is defined'
注意:不同版本的Nagios XI批量API端点可能有差异,你可以查一下官方文档确认具体的批量提交格式。
2. 正确使用异步并行请求
如果批量API不可用,那调整异步的使用方式,让所有请求同时发起,然后一次性等待所有任务完成,而不是逐个等待:
- name: 异步推送服务到Nagios delegate_to: localhost uri: url: "https://nagios/nagiosxi/api/v1/config/service?apikey={{ nagios_apikey }}&config_name={{ ansible_fqdn }}-fs-{{ item.mount | replace('/','-') }}" method: POST body_format: form-urlencoded body: # 保持原body参数不变 loop: "{{ ansible_mounts }}" vars: # 原vars不变 register: upload_tasks failed_when: 'upload.json is defined and upload.json.error is defined' when: item.fstype == 'xfs' or item.fstype == 'ext4' async: 60 poll: 0 - name: 等待所有异步推送任务完成 delegate_to: localhost async_status: jid: "{{ item.ansible_job_id }}" register: upload_results retries: 20 delay: 1 until: upload_results.finished loop: "{{ upload_tasks.results }}" # 可以加throttle控制并行等待的数量,避免同时发起太多状态查询请求 # throttle: 5
这样所有uri请求会同时后台运行,Ansible会并行等待它们完成,能有效利用网络并行性。不过要注意Nagios API的并发承受能力,如果并发太高导致API报错,可以调整throttle参数限制并行数。
3. 优化请求本身的耗时
- 关闭SSL证书验证(如果环境允许):加
validate_certs: no,减少证书校验的时间开销。 - 启用HTTP/2:如果Nagios服务器支持,加
http1: false,HTTP/2的多路复用能提升并发请求的效率。 - 预计算变量,减少循环内的模板渲染:你原任务中每个循环都要做大量的多层条件判断,这些判断每次循环都会重新计算,很耗CPU。可以提前用
set_fact把所有参数预计算好,循环时直接引用:
- name: 预计算所有挂载点的服务参数 set_fact: precomputed_mounts: "{{ precomputed_mounts | default([]) + [mount_params] }}" loop: "{{ ansible_mounts }}" vars: mount_params: mount: "{{ item.mount }}" fstype: "{{ item.fstype }}" warning: "{{ fs[ansible_fqdn][item.mount]['warning'] if ((fs is defined) and ansible_fqdn in fs and item.mount in fs[ansible_fqdn] and 'warning' in fs[ansible_fqdn][item.mount]) else fs['defaults']['warning']}}" critical: "{{ fs[ansible_fqdn][item.mount]['critical'] if ((fs is defined) and ansible_fqdn in fs and item.mount in fs[ansible_fqdn] and 'critical' in fs[ansible_fqdn][item.mount]) else fs['defaults']['critical']}}" initial_state: "{{ fs[ansible_fqdn][item.mount]['initial_state'] if ((fs is defined) and ansible_fqdn in fs and item.mount in fs[ansible_fqdn] and 'initial_state' in fs[ansible_fqdn][item.mount]) else service[env]['initial_state']}}" # 把所有需要的参数都预计算好 when: item.fstype == 'xfs' or item.fstype == 'ext4' # 然后在uri任务中直接引用precomputed_mounts的参数
4. 调整Ansible的forks参数
如果你的Playbook是针对多主机的,调整ansible.cfg中的forks值(默认是5),增加并行处理的主机数量。但如果是单主机内的循环,这个参数只影响异步任务的并行数,配合上面的异步方案使用效果更好。
最后再强调一下:批量请求是最优解,能从根本上减少请求次数;如果只能用并行异步,一定要确保Nagios API能承受并发压力,避免适得其反。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

