转载自(https://www.cnblogs.com/mauricewei/p/10056494.html)
当管理集群达到一定规模时,ansible达到性能瓶颈是难以避免的,此时我们可以通过一定手段提高ansible的执行效率和性能。
笔者虽未管理过超大规模服务器,但也通过查找资料和咨询大神了解了一些。现总结一些调优方法,供大家参考。
我们知道ansible执行一个模块要ssh到目的主机多次,开启「pipelining」特性实际上是通过减少ssh连接次数,从而缩短ansible执行时间。在部署大规模服务器或引用模块非常多时,开启「pipelining」特性会给ansible带来显著的性能提升。
开启方法也很简单,将ansible.cfg的pipelining参数设置为True即可,该参数默认值是False。
既然「pipelining」特性默认是关闭的,肯定有它的理由:关闭该特性可以与sudo的requiretty兼容(即/etc/sudoers配置文件的「Defaults requiretty」配置项)。大部分linux操作系统是默认开启requiretty功能的,所以pipelining也是默认False的。
也就是说,如果我们要开启pipelining特性,要么playbook不使用sudo越权功能,要么取消sudo的「requiretty」特性。
该特性可以通过命令行添加 -vvvv 后,根据执行结果对比出区别,因篇幅原因这里不再展示。
适用场景
control_path通过设置ControlPath sockets的文件路径与文件命名避免因sockets文件过长(超过108个字符串)导致ansible报错的问题。
设置方法为更改ansible.cfg里的control_path参数,ansible2.7版本默认值为「配置项control_path_dir的值」+「根据hostname生成的哈希值」+「ssh端口号」+「用户名」
在ansible旧版本中,默认值是包含主机名的,这在一些特殊情况下(例如EC2主机),会因主机名过长导致ControlPath sockets文件过长,从而导致ansible执行报错。但在新版本中默认值的主机名部分被替换为主机名的哈希值,这很大程度上避免了该问题的发生。
我们也可以设置其他的参数,例如:
control_path = %(directory)s/%%h-%%r
其中$directiry是control_path_dir的值,后面的参数可以灵活定制,可用参数如下:
%L 本地主机名的第一个组件
%l 本地主机名(包括域名)
%h 远程主机名(命令行输入)
%n 远程原始主机名
%p 远程主机端口
%r 远程登录用户名
%u 本地 ssh 正在使用的用户名
%i 本地 ssh 正在使用 uid
%C 值为 %l%h%p%r 的 hash
适用场景
当ansible报错并且使用 -vvvv 查看发现有类似「too long for Unix domain socket」的错误信息,我们应该想到这个调优方式。
Disable gather facts
在介绍Gather subset之前,我们先简单说下gather_facts功能,gather_facts用于控制一个play是否收集目的主机的facts信息(参考《ansible基础-变量》),默认值为true/True/yes,写法如下:
- hosts: nodes
gather_facts: True
tasks:
在playbook执行过程中,ansible收集facts变量是很耗时的一个步骤,如果我们确定play中没有用到fact变量信息,可以直接将其关闭,即将gather_facts设置为false/False/no。
Gather subset
但是在实际使用中不收集facts变量的情况很少。在gather_facts关闭的情况下,我们可以给play单独添加一个setup模块,并通过gather_subset参数严格控制facts的收集种类,这样既拿到了我们需要的fact变量又提高了ansible的执行效率,gather_subset参数的默认值为all。
playbook中使用方法示例:
- name: Collect only facts returned by facter
setup:
gather_subset:
- '!all'
- '!any'
- facter
命令行使用方法示例:
# Collect only facts returned by facter.
ansible all -m setup -a 'gather_subset=!all,!any,facter'
可用参数有all, min, hardware, network, virtual, ohai, facter,可以使用列表的格式指定多个参数,使用「!」指定不收集的facts类型。
比较常用的几个范例:
关于facts变量还有一个优化手段,即facts缓存。
fact缓存是指将收集到的facts信息缓存到本地json文件或者redis数据库内,以便下次执行直接读取,从而提高执行效率。
关于facts缓存,我们在《ansible基础-变量》6.1.2 facts缓存有详细介绍,在这里就不再重复介绍了。
s trategy的作用范围是一个play,通过设置不同参数,控制一个play内所有任务的执行策略。
设置方法为更改ansible.cfg里的strategy参数,默认值为linear,可选参数为free;另外一种方式是在playbook内定义该策略,格式为:
- hosts: all
strategy: free
tasks:
...
参数含义:
free策略即自由策略,即在一个play执行完之前,每个主机都各顾各的尽可能快的完成play里的所有任务,而不会因为其他主机没执行完任务而等待,不受线性执行策略那样的约束。所以这种策略的执行结果给人感觉是无序的甚至是杂乱无章的,而且每次执行结果的task显示顺序很可能不一样。
举个,展示下两种策略的执行效果:
playbook要实现的是三台主机debug出test_1,test_2,test_3三个字符串。当使用linear策略时,执行效果如下:
执行结果
当使用free策略时,执行效果如下:
执行结果
从上面两个个执行结果很明显的能看出区别,linear策略是遵循第一个任务、第二个任务、第三个任务……这样顺序执行下去的,而free策略则是无序的,甚至Gathering Facts任务也可能在debug任务之后执行。
forks用来设置同一时刻与目的主机连接数,也可以理解为主机并行数,默认值比较保守为5。在生产中,多数情况下我们会更改这个参数。如果控制节点的CPU和网络性能够用,设置几十上百个也是可以的。
在ansible.cfg设置forks的全局默认值:
# ansible.cfg
[defaults]
forks = 15
命令行设置forks的数量,即在执行playbook时,通过「--forks」或「-f」指定:
lab-ansible ansible-playbook playbooks/test_forks.yaml --fork 10
serial用于控制一个play内的主机并行数,这个并行数不能超过forks,超过后则serial不会生效。
定义方法如下:
--
- hosts: nodes
serial: 2
tasks:
本质上,serial作用范围是一个play,受限于forks,但比forks控制的更加细节。假如我们的forks设置为100,但是想让某个play里的所有任务并行数为50的执行,此时我们应该想到serial这个调优方法。
同步阻塞模式和异步模式
异步模式指ansible将一次性运行所有的任务,并将所有的任务丢到后台执行,每个任务有一个job_id,ansible会根据这个job_id每隔一段时间轮训检测该任务的执行情况,直到检测到任务执行结束。这种模式称为异步模式。
Async and pool
前面章节我们所说的Strategy、Forks、Serial都是ansible同步阻塞模式下的优化方法,其中,strategy是通过控制任务执行策略进行优化,forks和serial是通过控制并行数进行优化。
针对某些特殊任务,尤其是可能被锁住或超时的任务,我们可以采用ansible异步模式来提高执行效率。
async和poll分别用来指定异步模式下任务的最大运行时间和检测间隔时间,poll的缺省值为10。
示例如下:
---
- hosts: all
remote_user: root
tasks:
- name: simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec
command: /bin/sleep 15
async: 45
poll: 5
该示例中sleep命令采用异步的方式执行,ansible会等待该任务最长45秒,每隔5秒钟检测一次任务的执行结果。
特殊情况下,我们可以将poll的值设置为0,这代表ansible将任务放到后台后,不会再管这个任务的执行状态,任其自生自灭。
这里举一个利用异步重启服务器的例子,因篇幅原因,仅给大家展示部署代码,就不贴执行结果了,如果您感兴趣,可以亲自实践下:
---
- hosts: node1
gather_facts: no
tasks:
- shell:
cmd: grub2-set-default 0
notify:
- reboot
- wait for reboot
- wait for ssh start
handlers:
- name: reboot
shell:
cmd: shutdown -r now "Reboot triggered by ansible"
async: 1
poll: 0
ignore_errors: True
- name: wait for reboot
wait_for_connection:
timeout: 300
- name: wait for ssh start
wait_for:
host: node1
state: started
delay: 10
port: 22
timeout: 30
如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!
赞3
添加新评论0 条评论