Ansible 执行过程分析、异步、效率优化
  hkpisnbYHqKn 2023年11月13日 23 0

直观观察任务执行速度插件

callback_whitelist = profile_tasks, profile_roles, timer

该插件可以直接统计每个task,每个role,每个play执行的时间,方面观察出哪些任务耗时


Ansible 执行过程分析

下面是2.9的默认执行过程分析(简单分析,具体请vvv):

  1. 获取用户家目录,此处为/root
  2. 在家目录下创建临时目录,临时目录由配置文件中remote_tmp指令控制
  3. 探测目标节点的平台和python解释器的版本信息
  4. 将要执行的模块相关的代码和参数放到本地临时文件中,并使用sftp将任务文件传输到被控节点的临时文件中
  5. 对目标节点上的任务文件授以执行权限
  6. 执行目标节点上的任务
  7. 删除目标节点上的临时目录


Ansible 执行策略

默认情况下 forks=5,这表明在某一时刻最多只有 5 个执行任务的工作进程 (还有一个主进程),也即最多只能挑选 5 个节点同时执行任务。

serail 是 play 级别的指令,用于指定几个节点作为一批去执行该 play,该 play 执行完后才让下一批节点执行该 play 中的任务。如果不指定 serial,则默认的行为等价于将所有节点当作一批。

strategy 指令用于指定节点执行任务时的策略,其侧重点在于节点而在于任务,默认情况下其策略为 linear,表示某个节点先执行完一个任务后等待其余所有节点都执行完该任务,才统一进入下一个任务。另一种策略是 free 策略,表示某节点执行完一个任务后不等待其它节点,而是毫不停留的继续执行该 play 中的剩余任务,直到该 play 执行完成,才释放节点槽位让其它未执行任务的节点开始执行任务。

默认情况下 Ansible 会让所有节点 (或者 serial 指定的数量) 执行完同一个任务后才让它们进入下一个任务,这体现了各节点的公平性和实时性:每个节点都能尽早执行到任务。这其实和操作系统的进程调度是类似的概念,只不过相对于操作系统的调度系统来说,Ansible 的调度策略实在是太简陋了。

假设 forks 设置的比较大,可以一次性让足够多的节点并发执行任务,那么同时设置任务的执行策略为 strategy=free 便能让这些执行任务的节点彻底放飞自我。只是剩余的一部分节点可能会比较悲剧,它们处于调度不公平的一方。但是从整体来说,先让大部分节点快速完成任务是值得的。

但是要注意,有些场景下要小心使用 free 策略,特别是节点依赖时。比如,某些节点运行服务 A,另一些节点运行服务 B,而服务 B 是依赖于服务 A 的,那么必须不能让运行 B 服务的节点先执行,对于有节点依赖关系的任务,为了健壮性,一般会定义好等待条件,但是出现等待有可能就意味着浪费。


ansible并发和异步

Ansible 允许在 task 级别指定该 task 是否以异步模式

在异步执行任务时,需要注意那些有依赖性的任务。对于那些对资源要求占有排它锁的任务,如yum,不应该将Poll的间隔设置为0。如果设置为0,很可能会导致资源阻塞。

异步模式下,ansible会将节点的任务丢在后台,每台被控制的机器都有一个job_id,ansible会根据这个job_id去轮训该机器上任务的执行情况,例如某机器上此任务中的某一个阶段是否完成,是否进入下一个阶段等。即使任务早就结束了,但只有轮训检查到任务结束后才认为该job结束。可以指定任务检查的时间间隔,默认是10秒。除非指定任务检查的间隔为0,否则会等待所有任务都完成后,ansible端才会释放占用的shell。

如果指定时间间隔为0,则ansible会立即返回(至少得连接上目标主机,任务发布成功之后立即返回),并不会去检查它的任务进度。

总结来说,大概有以下一些场景需要使用到ansible的异步特性:

  • 某个task需要运行很长的时间,这个task很可能会达到ssh连接的timeout
  • 没有任务是需要等待它才能完成的,即没有任务依赖此任务是否完成的状态
  • 需要尽快返回当前shell

当然也有一些场景不适合使用异步特性:

  • 这个任务是需要运行完后才能继续另外的任务的
  • 申请排它锁的任务

实例:

- name: Asynchronous yum task
  yum:
    name: nginx
    state: present
  async: 1000
  poll: 0
  register: yum_sleeper

- name: Wait for asynchronous job to end
  async_status:
    jid: '{{ yum_sleeper.ansible_job_id }}'
  register: job_result
  until: job_result.finished
  retries: 30

开启 ssh 长连接

Ansible 对 ssh 的依赖性非常强,优化 ssh 连接在一定程度上也是在优化 Ansible。

其中一项优化是开启 ssh 的长连接,即长时间保持连接状态。开启长连接后,在 ssh 连接过期前会一直保持 ssh 连接已建立的状态,使得下次和目标节点建立 ssh 连接时将直接使用该连接。相当于对 ssh 连接进行了缓存。

要开启 ssh 长连接,要求 Ansible 端的 openssh 版本高于或等于 5.6。使用 ssh -V 可以查看版本号。然后设置 ansible 使用 ssh 连接被控端的连接参数,此处修改 /etc/ansible/ansible.cfg,在此文件中启动下面的连接选项,其中 ControlPersist=5d 是控制 ssh 连接会话保持时长为 5 天。


开启 Pipelining

从前面对 Ansible 执行任务的流程中可以发现,Ansible 执行每个任务时都会在本地将模块 (通常是 Python 脚本程序) 和相关参数打包后通过 sftp 发送到目标节点上,然后执行目标节点上的临时脚本文件。这些行为还带来了副作用,比如多建立了几个 ssh 连接来创建临时目录、删除目录等。

Ansible 现在也支持使用 ssh 的 pipelining 特性 (注意,仍然是 ssh 的特性),当 Ansible 中开启了 Pipelining 后,一个任务的所有动作都在一个 ssh 会话中完成,也会省去 sftp 到远端的过程,它会直接将要执行任务涉及到的指令 (比如 python 语句) 通过远程 shell 的方式发送到目标节点的标准输入 (stdin) 中,然后在目标节点执行这些代码。

但是要注意,如果在ansible中使用sudo命令的话(ssh user@host sudo cmd),需要在被控节点的/etc/sudoers中禁用"requiretty"。

之所以要设置/etc/sudoers中的requiretty,是因为ssh远程执行命令时,它的环境是非登录式非交互式shell,默认不会分配tty,没有tty,ssh的sudo就无法关闭密码回显(使用"-tt"选项强制SSH分配tty)。所以出于安全考虑,/etc/sudoers中默认是开启requiretty的,它要求只有拥有tty的用户才能使用sudo,也就是说ssh连接过去不允许执行sudo。可以通过visudo编辑配置文件,注释该选项来禁用它。

#Defaults    requiretty


设置facts缓存

Ansible 默认会收集所有节点的所有 facts 信息,而收集 facts 信息是非常慢的。

如果能够确保 play 中使用不到 facts 中的信息,则可以 gather_facts: no 关闭收集功能。

如果只想要 facts 中的一部分信息,那么在收集时可以指定只收集这一部分信息,其它的不要收集。例如只想收集网卡相关信息可以设置 gather_subset=!all,!any,network,这样可以减少收集的数据量,从而提升效率。


第三方策略插件:Mitogen for Ansible

Ansible 的执行策略 (即由 strategy 指令指定的值) 是以插件方式提供的。Ansible 官方目前提供了四种策略插件:

  • (1).linear
  • (2).free
  • (3).host-pinned
  • (4).debug

安装然后在 ansible.cfg 中设置使用该策略插件,并指定该策略插件提供的策略。

提升速度比较明显,但是可能影响一些原生的ansible模块,注意阅读官方文档,建议在网络环境比较好的情况下使用。

官方介绍和文档:Mitogen for Ansible–https://mitogen.networkgenomics.com/ansible_detailed.html

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

推荐阅读
  QoiZfapeULCM   2023年11月02日   51   0   0 Ansible
  TNZdNLJrAgNB   2023年11月13日   20   0   0 Ansible
  TNZdNLJrAgNB   2023年11月02日   49   0   0 Ansible
  TNZdNLJrAgNB   2023年11月02日   57   0   0 Ansible