當管理集羣達到必定規模時,ansible達到性能瓶頸是難以免的,此時咱們能夠經過必定手段提升ansible的執行效率和性能。html
筆者雖未管理過超大規模服務器,但也經過查找資料和諮詢大神瞭解了一些。現總結一些調優方法,供你們參考。node
咱們知道ansible執行一個模塊要ssh到目的主機屢次,開啓「pipelining」特性其實是經過減小ssh鏈接次數,從而縮短ansible執行時間。在部署大規模服務器或引用模塊很是多時,開啓「pipelining」特性會給ansible帶來顯著的性能提高。linux
開啓方法也很簡單,將ansible.cfg的pipelining參數設置爲True便可,該參數默認值是False。redis
既然「pipelining」特性默認是關閉的,確定有它的理由:關閉該特性能夠與sudo的requiretty兼容(即/etc/sudoers配置文件的「Defaults requiretty」配置項)。大部分linux操做系統是默認開啓requiretty功能的,因此pipelining也是默認False的。shell
也就是說,若是咱們要開啓pipelining特性,要麼playbook不使用sudo越權功能,要麼取消sudo的「requiretty」特性。數據庫
該特性能夠經過命令行添加 -vvvv 後,根據執行結果對比出區別,因篇幅緣由這裏再也不展現。json
適用場景緩存
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緩存有詳細介紹,在這裏就再也不重複介紹了。
strategy的做用範圍是一個play,經過設置不一樣參數,控制一個play內全部任務的執行策略。
設置方法爲更改ansible.cfg裏的strategy參數,默認值爲linear,可選參數爲free;另一種方式是在playbook內定義該策略,格式爲:
- hosts: all strategy: free tasks: ...
參數含義:
舉個🌰,展現下兩種策略的執行效果:
playbook要實現的是三臺主機debug出test_1,test_2,test_3三個字符串。當使用linear策略時,執行效果以下:
➜ lab-ansible ansible-playbook playbooks/test_trategy.yaml PLAY [nodes] *********************************************************** TASK [Gathering Facts] *********************************************************** ok: [node3] ok: [node2] ok: [node1] TASK [debug] *********************************************************** ok: [node1] => { "msg": "test_1" } ok: [node3] => { "msg": "test_1" } ok: [node2] => { "msg": "test_1" } TASK [debug] *********************************************************** ok: [node1] => { "msg": "test_2" } ok: [node3] => { "msg": "test_2" } ok: [node2] => { "msg": "test_2" } TASK [debug] *********************************************************** ok: [node1] => { "msg": "test_3" } ok: [node3] => { "msg": "test_3" } ok: [node2] => { "msg": "test_3" } PLAY RECAP *********************************************************** node1 : ok=4 changed=0 unreachable=0 failed=0 node2 : ok=4 changed=0 unreachable=0 failed=0 node3 : ok=4 changed=0 unreachable=0 failed=0
當使用free策略時,執行效果以下:
PLAY [nodes] *********************************************************** TASK [Gathering Facts] *********************************************************** ok: [node3] ok: [node2] TASK [debug] *********************************************************** ok: [node3] => { "msg": "test_1" } ok: [node2] => { "msg": "test_1" } TASK [Gathering Facts] *********************************************************** ok: [node1] TASK [debug] *********************************************************** ok: [node3] => { "msg": "test_2" } ok: [node2] => { "msg": "test_2" } TASK [debug] *********************************************************** ok: [node1] => { "msg": "test_1" } TASK [debug] *********************************************************** ok: [node3] => { "msg": "test_3" } ok: [node2] => { "msg": "test_3" } TASK [debug] *********************************************************** ok: [node1] => { "msg": "test_2" } TASK [debug] *********************************************************** ok: [node1] => { "msg": "test_3" } PLAY RECAP *********************************************************** node1 : ok=4 changed=0 unreachable=0 failed=0 node2 : ok=4 changed=0 unreachable=0 failed=0 node3 : ok=4 changed=0 unreachable=0 failed=0
從上面兩個個執行結果很明顯的能看出區別,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這個調優方法。
同步阻塞模式和異步模式
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
歡迎你們關注個人公衆號: