Advacned Puppet: Puppet Master性能調優


本文是Advanced Puppet系列的第一篇:Puppet master性能調優,談一談如何優化和提高C/S架構下master端的性能。

故事情節往往驚人地類似:你是一名使用Puppet管理線上業務的DevOps工程師,隨着公司的業務發展,你所管理的集群規模日益擴大。終於某一天,你突然發現執行一次puppet agent -vt的時間長得不可接受,多台agent並發運行時竟然會有節點運行失敗,往日從來沒有考慮過Puppet的性能居然成為了瓶頸……首先要恭喜你,因為Puppet Master端的性能瓶頸只有在集群發展到一定規模時才會遇到。

 

Tuning

    圖1 性能調優

籠統地去談系統的性能調優,是一個泛泛的話題,陳皓在他的《性能調優攻略》中介紹了系統性能的定義和如何定位性能瓶頸。因此,本篇把討論范圍縮小:只關注master端的性能調優,而不涉及Puppet代碼的執行效率調優,部署邏輯的調優等等。

我們要對Puppet進行優化前,首先要清楚它有哪些瓶頸。對Puppet的C/S架構所有了解后,我們把它歸類到Web服務: puppet agent端向puppet master發送請求,puppet master端處理請求並返回結果。web服務常見的性能度量指標是響應時間,系統吞吐量,系統資源利用率,並發用戶數等。那么在這里我們主要關注兩個指標:響應時間和並發用戶數。因此,在對Puppet Master進行調優前,需要了解agent端和master端是如何交互的。

image圖2 Puppet C/S架構下的處理流程圖

從圖2可以看到一次完整的agent請求catalog的具體流程,Agent和Master之間的交互可以分為三步:

      1. agent先向master發送一個請求,希望獲取自己的catalog;

      2. Master端通過agent附帶的fqdn,environment等facts信息判斷節點的分類,隨后對其所屬的class,define等資源進行編譯;處理完成后把catalog以json格式返回給agent端;

      3. Agent端拿到catalog后先做一個本地的狀態查詢,然后進行收斂達到預期的狀態,完成后發送一個本次執行概況的report給Master端

 

ok,那我們來看一下實際的運行結果是如何的:以一台RabbitMQ節點向PuppetMaster發起一次執行操作為例,先分析Server端的訪問日志有哪些操作:

10.0.1.45 - - [15/Aug/2014:23:31:50 -0400] "GET /production/node/server-45.1.test.ustack.in? HTTP/1.1" 200 4473 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:31:50 -0400] "GET /production/file_metadatas/plugins?links=manage&recurse=true&checksum_type=md5&ignore=.svn&ignore=CVS&ignore=.git HTTP/1.1" 200 149510 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:31:52 -0400] "POST /production/catalog/server-45.1.test.ustack.in HTTP/1.1" 200 305052 "-" "-" 7 
10.0.1.45 - - [15/Aug/2014:23:32:03 -0400] "GET /production/file_metadata/modules/rsyslog/rsyslog_default?links=manage HTTP/1.1" 200 317 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:32:03 -0400] "GET /production/file_metadata/modules/ssh/sshd_config?links=manage HTTP/1.1" 200 309 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:32:04 -0400] "GET /production/file_metadata/modules/ssh/ssh_config?links=manage HTTP/1.1" 200 308 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:32:04 -0400] "GET /production/file_metadatas/modules/mcollective/site_libdir?links=manage&recurse=true&checksum_type=md5 HTTP/1.1" 200 650 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:32:04 -0400] "GET /production/file_metadatas/modules/mcollective/plugins/actionpolicy?links=manage&recurse=true&checksum_type=md5 HTTP/1.1" 200 1740 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:32:07 -0400] "GET /production/file_metadata/modules/logrotate/etc/logrotate.conf?links=manage HTTP/1.1" 200 322 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:32:07 -0400] "GET /production/file_metadata/modules/logrotate/etc/cron.hourly/logrotate?links=manage HTTP/1.1" 200 329 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:32:07 -0400] "GET /production/file_metadata/modules/logrotate/etc/cron.daily/logrotate?links=manage HTTP/1.1" 200 328 "-" "-" 0 
10.0.1.45 - - [15/Aug/2014:23:32:07 -0400] "PUT /production/report/server-45.1.test.ustack.in HTTP/1.1" 200 11 "-" "-" 0

再來看agent端的輸出日志:

time puppet agent -vt 

Info: Retrieving plugin
Info: Caching catalog for server-45.1.test.ustack.in 
Info: Applying configuration version '1408154486' 
Notice: Finished catalog run in 4.57 seconds

real    0m17.579s 

所謂catalog的編譯,實質上是生成一個資源執行的有向狀態圖,是一個消耗CPU和磁盤IO資源的計算操作。在一次沒有任何變更操作的情況,Puppet在分類和編譯catalog上花費了整整11秒的時間,而作為文件服務器向agent端提供文件下載只花費了4秒,那么我們能從哪些方面來縮短master的響應時間?首先我們要分析慢在哪里,有哪些可能的原因會導致運行速度慢?

 

1. 升級軟件版本

根據我的交流發現有不少公司仍在使用2.x版本的puppet,尤其以2.7.x居多。因為在Ubuntu/CentOS下,使用默認源安裝的puppet版本就是2.7(6).x。根據官方的3.x Release Note,3.x的性能相比2.x相比有非常顯著的提升,尤其是與2.7.x相比有50%的提升,我們目前使用的Puppet版本是3.3.1,實測結果是:相比2.7.14,整體的執行速度約提升了30%(與具體的部署邏輯相關)。

升級帶來另外一個重要的問題:兼容性。我們知道把一個項目從Python2.7升級到Python3.4是一個非常困難的事情,某些語法的變更,最讓人頭疼的是大量的第三方庫並不支持3.x。但是從Puppet 2.7(6).x升級到3.x你不需要太擔心兼容性問題,因為絕大多數的puppet modules支持3.x的puppet語法規范。可能需要變動的是你自己編寫的模塊,例如模板,變量的命令空間等一些變動,並且這些兼容性問題只是以warning的形式提醒你進行修改。

 

2. 設置客戶端合理的運行間隔

常常有不少同學喜歡把puppet agent端的運行間隔runinterval參數設置得很短,例如180s甚至60s。他們希望通過這種不停運行agent的方式,一是能夠替代主動推送的需求,二是可以做到當服務意外停止,配置文件被人為修改后,可以盡快地恢復。這些想法並不能滿足上述需求。

首先,推和拉是兩個不同的操作模式,若以頻繁的被動拉取節點配置來替代主動推送帶來了幾個問題:

    1. 無意義地浪費server端的性能,從前面的數據中可以得知編譯catalog是一個非常耗資源的操作;

    2. 線上的一切變更均屬於嚴肅的變更流程,需要主動地控制升級策略,例如兩個web服務節點的升級流程,先得把web-01從lb背后摘下,進行變更,然后再重新上線,接着對web-02做同樣的操作,拉模型明顯不符合這樣的部署需求;

    3. 服務監控屬於監控體系來管理,讓puppet來做,心有余而力不足;

一個合理的runinterval值應該根據集群的規模來進行調整,官方的推薦值是1800s。

 

3.設置Splay避免驚群效應

舉個簡單的例子,當你往一群鴿子中間扔一塊食物,雖然最終只有一個鴿子搶到食物,但所有鴿子都會被驚動來爭奪,沒有搶到食物的鴿子只好回去繼續睡覺, 等待下一塊食物到來。這樣,每扔一塊食物,都會驚動所有的鴿子,稱為驚群。對於PuppetMaster來說,多個puppetmaster進程在等待CPU和IO資源時也會產生類似的情況。

在搭建內部開發環境的初期,我對puppet agent的運行間隔設置隨意設置了一個較短的值:300s。本以為大功告成,但是當集群規模增加了一倍后,我發現agent從Puppet Master獲取一次catalog的時間超過了我的預期。通過分析apache日志我才發現,所有節點幾乎在同個時間段向這台可憐的PuppetMaster發出了請求,瞬間把這台運行在hypervisor上的master的CPU資源跑滿。解決這個問題的辦法就是設法錯開Agent的拉取時間點,puppet默認提供了splay參數來滿足這個需求。

你需要在每台agent節點的puppet配置文件中,添加:

splay = true

還有一個splaylimit參數,若不設置則默認會取runinterval的值。Puppet agent每次會在runinterval的基礎上,增加0~splaylimit(秒)間的隨機值后再運行,大大降低了agent同一時刻運行的概率。

 

4.棄用Webrick

很多同學喜歡使用ruby自帶的webrick webserver來啟動puppetmaster服務,因為簡單方便。例如:

service puppetmaster start

首先,你要明白一點的是這些語言的內置webserver目的僅是為了方便調試代碼,是根本不能放到生產環境去使用。

使用WebRick運行的Puppetmaster性能有多差?

僅9個並發請求就能把它拖垮。

我在在一台E5 2620的服務器上試驗:只要9個puppet agent同時向運行在webrick上的puppet master發送請求,就處理不過來了,你會發現總有某台agent會出現40x Error的錯誤。

要提高單台Puppetmaster的性能很簡單,只要使用常見的Web Server軟件就可以顯著地提高Puppet master的性能,例如Apache,Nginx等。這類文檔很多,這里就不再詳細說明配置的步驟了。

 

5.禁止使用activerecord + SQL作為Storeconfigs Backend

當你在開啟了storeconfigs來使用Puppet的一些高級特性時,請注意不要使用activerecord + SQL的組合作為其后端存儲。這對組合常常在2.x版本中出現得比較多,因為那時它的替代品PuppetDB還沒有成熟,我們也曾經使用了近一年的ActiveRecord + MySQL的方式來做后端存儲,它的目的就是把生成的catalog,facts等等都存到數據庫中,其性能就是慢,慢,慢。去年我們在做私有雲項目時,起初部署一台控制節點,竟然要30分鍾!慢到老大一度想要用shell腳本去取代puppet,一度讓我想把代碼中所有高級特性全部禁用。我不得不尋求其他替代技術來改善storeconfigs的運行效率。

Puppet 3.x升級的另一個特性就是把這些老古董標記為棄用,當時社區推出了PuppetDB + PostgreSQL的新組合,其目的就是為了替代它們的。在執行存儲和查詢操作時,性能上提升不止快了一倍,最終交付給用戶的時候,部署時間下降到了18分鍾。不過,我已經忘記把測試對比數據丟哪了,可能是隨ActiveRecord + MySQL一起丟了 :D。

 

6. 橫向擴展Puppet集群

經過上述的優化后,你通過觀察CPU負載發現單台Puppet已無法管理當前的集群規模時,可以對Puppet進行橫向擴展。web服務的性能擴展較為容易,通過簡單地增加puppet master節點的數量就能輕松地提高處理能力。在前端放置七層負載均衡,用於處理SSL認證和轉發請求。如何搭建Puppet集群,如何在前端設置七層負載均衡的配置過程,我之前已寫過相關的文章,也可以通過網上找到相應的資料。

 

 

image

圖3 Puppet集群的典型架構圖

 

7. 縱向擴展與橫向擴展PuppetDB服務

當你選擇使用PuppetDB作為storeconfigs的組件時,那么PuppetDB將是Puppet部署中的重要組件,如果PuppetDB掛了,那么agent節點將無法得到catalog。PuppetDB節點是屬於典型的耗CPU,耗內存,耗磁盤IO的資源使用大戶。下面我們來看看實際使用中可能會遇到的瓶頸以及解決辦法。

image 圖4 PuppetDB性能監控面板

7.1 數據庫的性能瓶頸

PuppetDB主要作用是存儲和查詢catalog,facts和reports,其主要瓶頸主要在於后端PostgreSQL的讀寫性能,我們不可能花費精力去做PG的性能調優,需要找一種廉價的方式來提高性能。我的老大常常教育我,如果錢能解決的問題,那都不是事兒。因此若通過縱向擴展就能解決問題,其實是一種非常經濟的手段:D。因此在生產環境中,推薦使用企業級的SSD盤去替代SATA盤,否則隨着集群規模的增加,大量的隨機讀寫操作會讓PostgreSQL慢如蝸牛。

 

7.2 Java Heap大小的瓶頸

在使用PostgreSQL的情況下,分配128MB內存作為基礎,然后根據集群的規模來增加額外的內存配置,原則是為每一台puppet node分配1M內存。然后通過觀察PuppetDB的性能檢測面板再進行適當地調整。修改方式是編輯puppetdb的啟動腳本,修改JAVA_ARGS參數,為其分配2G內存:

JAVA_ARGS="-Xmx2g"

 

7.3 PuppetDB worker進程數的瓶頸

PuppetDB可以有效利用多核來處理其隊列中的請求,每個核可以運行一個worker進程,PuppetDB默認只會運行該台機器一半核數的worker。因此,當你發現PuppetDB的性能監控面板上queue depth值長時間不為0時,你就需要配置更多的worker數。

                  圖5 Command Queue 監控圖

那如果單台PuppetDB不能滿足需求了,如何處理? 那就需要橫向擴展PuppetDB,構建PostgreSQL集群,其實大可不必如此憂愁。Puppetlabs官方給出的數據是使用一台2012年的筆記本 (16 GB of RAM, consumer-grade SSD, and quad-core processor)運行PuppetDB和PostgreSQL足以支撐8000台Puppet nodes每30分鍾一次的運行。

 

8 總結

    本篇中,我們先后從軟件版本的升級,相關參數的調整,選擇Web服務器作為容器,橫向擴展,縱向擴展,后端存儲的替換等多個方面考慮去提高Puppetmaster端的性能,具體到生產環境中,實際情況會所有不同,但是方法都是相同的:分析問題本質,找出問題所在,確定合理的優化方案。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM