使用async仍存在Ansible多主机任务调用延迟,如何优化?
如何减少Ansible中带
with_items的异步REST API调用延迟? 我来帮你分析问题根源,以及对应的解决办法:
首先看你的场景:你用Ansible的uri模块配合async/poll批量调用多节点的REST API,但日志里每个任务项之间有2-3秒的延迟,和预期的无延迟调用不符。
先贴出你的任务代码:
- name: Perform operation on Multiple Nodes uri: url: "http://{{item.ipAddress}}:{{item.port}}/api/internal/operations" method: POST body: "{{jobData}}" headers: Accept: "******/*******.{{resource}}.{{resourceVersion}}+json" status_code: 200 body_format: json when: (item.ipAddress is defined) and (item.port is defined) with_items: '{{nodeData}}' async: '{{connectionTimeout | int}}' poll: 1 register: instances ignore_errors: True
以及显示延迟的日志片段:
2018-05-28 *11:26:51* ,530 p=7744 u=ops | TASK [Perform operation on Multiple Nodes] ************************************* 2018-05-28 *11:26:53* ,871 p=7744 u=ops | ok: [localhost] => (item={u'a': u'host0', u'ipAddress':', u'port': u''}) 2018-05-28 *11:26:56* ,095 p=7744 u=ops | ok: [localhost] => (item={u'a': u'host1', u'ipAddress': u'', u'': u''}) 2018-05-28 *11:26:58* ,324 p=7744 u=ops | ok: [localhost] => (item={u'a': u'host2', u'ipAddress': u'', u'port': u''})
问题根源
你可能误以为async会让with_items的任务并行执行,但实际上默认情况下,with_items会串行处理每个任务项,哪怕用了async。Ansible会先启动第一个异步任务,等它完成第一次poll(也就是你设置的poll:1的1秒等待),再启动第二个任务,以此类推——这就是每个调用间出现2-3秒延迟的核心原因。
解决办法
1. 推荐方案:使用async_batch(Ansible 2.10+)
如果你用的是Ansible 2.10或更高版本,直接用新增的async_batch参数就能实现批量并行启动异步任务,无需拆分任务:
- name: Perform operation on Multiple Nodes uri: url: "http://{{item.ipAddress}}:{{item.port}}/api/internal/operations" method: POST body: "{{jobData}}" headers: Accept: "******/*******.{{resource}}.{{resourceVersion}}+json" status_code: 200 body_format: json when: (item.ipAddress is defined) and (item.port is defined) with_items: '{{nodeData}}' async: '{{connectionTimeout | int}}' poll: 1 async_batch: 5 # 一次性启动5个异步任务,可根据你的节点数量调整 register: instances ignore_errors: True
这个参数会让Ansible同时启动指定数量的异步任务,彻底消除串行带来的延迟。
2. 兼容旧版Ansible:拆分任务为「启动+等待」两步
如果你的Ansible版本低于2.10,可以把任务拆成两步:先批量启动所有异步任务(不等待),再统一检查任务状态:
第一步:批量启动所有异步任务(并行)
- name: Start operation on all nodes uri: url: "http://{{item.ipAddress}}:{{item.port}}/api/internal/operations" method: POST body: "{{jobData}}" headers: Accept: "******/*******.{{resource}}.{{resourceVersion}}+json" status_code: 200 body_format: json when: (item.ipAddress is defined) and (item.port is defined) with_items: '{{nodeData}}' async: '{{connectionTimeout | int}}' poll: 0 # 立即返回,不等待任务执行,直接启动所有任务 register: async_jobs ignore_errors: True
第二步:统一等待所有任务完成
- name: Wait for all operations to finish async_status: jid: "{{ item.ansible_job_id }}" register: async_results until: async_results.finished retries: "{{ connectionTimeout | int // 1 }}" # 根据超时时间设置重试次数 delay: 1 with_items: "{{ async_jobs.results }}" when: item.ansible_job_id is defined
这种方式下,第一步会瞬间启动所有异步任务(没有串行间隔),第二步统一轮询所有任务的状态,完美解决延迟问题。
3. 额外优化:调整Ansible forks数量
别忘了确保Ansible的forks参数(默认是5)足够大,能支撑你需要并行的任务数。可以在ansible.cfg里配置:
[defaults] forks = 10 # 数值根据你的节点数量和服务器资源调整
或者运行playbook时临时指定:
ansible-playbook your_playbook.yml --forks 10
内容的提问来源于stack exchange,提问作者sks
相关产品推荐
相关产品推荐

