最近與同事教調了一個自製的小型分散式系統的效能,該系統以 Python + Gearman 兜成,所以使用了幾個 Python 的工具去作 profiling。雖然用到的工具對 Python hacker 來說很基本,但我覺得有幾點記錄下來頗有價值:
- 首先,這個系統有好幾台機器,其中一台是 gearman job server ,作為 job queue 的控管中心,其他台機器上有多個獨立的 process(gearman 中稱為 worker),每個 worker 從 job sever 收到要處裡的工作與資料,處理完後傳回給 job sever ,然後 job server 再繼續決定下一個 worker,概念上就跟 pipe 一樣, 只是分散到多台機器上同時執行而已,有興趣的朋友可以參考 gearman 的文件說明。問題來了,當 worker 的效能低落時,瓶頸在哪?要如何系統地判斷?
- 一開始我們試著先簡化測試用例,以方便快速複製與測試。 首先,設計一個只從 job server 收資料,但完全不作事的 worker。從這個實驗我們發現,在我們的網路環境下,數MB的 raw data 便可能造成很大的延遲。所以應該修正這點就能改善。
- 在 Python-gearman (gearman client 端的 Python 實現)中,我們發現每次從單一 job server 收取 4KB 的資料後,client 就會遷換到另一個 job server 收取另外一個 task 的 4KB 資料。這在資料量小時很合理,可以避免單一 worker 因服務某特定 job server 過久,而讓其他 job server 上的 task 飢餓。但在資料量的 throughput 為主要應用情境下,不斷地切換,只會造成不必要的浪費。所以我們將這個值往上調整到 64KB。
- 在我們的簡單 worker 中,這個調整帶來十幾倍的改進,但套用複雜的 worker 時,依然沒有明顯改善,可見得瓶頸在我們的 worker 本身。所以便祭出 cProfile 來量測。量測結果發現,除了網路 IO 以外,其他多個 function 很平均地佔了數個百分比,但是多數是個位數,似乎沒有哪個是主要的瓶頸?
- 有時,一圖值千金。我們為不好閱讀的 profile 檔案畫出 callgraph (推薦 Gprof2dot ),從圖形就可以很明顯地看出主要的問題集中在兩個以上的 functions,而那兩個 functions 底下分別呼叫的其他 functions 雖然都沒有佔據大比例的時間,但累加的效果卻相當驚人。針對個別 functions 以不同機制改善後,效能顯著提升數倍。
這次的經驗讓我再次確認幾個原則:
- 測試數據,不要用猜的。
- 不要輕易假定效能瓶頸只在一處。
- 簡單的測試用例有好處,但是並不能代表實際狀況。
- 善用成熟的工具。
當效能瓶頸在多處出現時,簡單的"一次僅改變一個地方"的原則需要調整,否則無法在修改一處後看到改善,就可能會誤以為修改到錯誤地方。善用工具可以幫助我們系統地進行此項工作,而不至於胡亂猜測。
留言
張貼留言