前不久,我寫了一篇《Fabric教程》,簡單來講,它是一個用 Python 開發的輕量級的遠程系統管理工具,在遠程登陸服務器、執行 Shell 命令、批量管理服務器、遠程部署等場景中,十分好用。shell
Fabric 2 是其最新的大版本,跟早前的 Fabric 1 有挺大的不一樣,更加好用了,可是沒填上的坑也挺多的……服務器
本文繼續來聊聊 Fabric,不過我不想再面面俱到了,而是專一於這一個話題:它是如何實現對批量服務器的串行/併發管理的?網絡
(友情提示:爲了有更好的閱讀體驗,若是你還不瞭解 Fabric 的基礎用法,建議先閱讀前面的教程。)數據結構
Fabric 經過 Group 來組合多臺服務器。區別在於由 fabric.group.Group 基類(父類)派生出的兩個子類:多線程
下面先看看這個基類:併發
我把一些沒用的信息摺疊了,比較值得注意的內容有:app
有了這個基類,接下來就要看 SerialGroup 和 ThreadingGroup 的具體實現了。工具
SerialGroup 類很簡單,只實現了一個 run() 方法。由於類在初始化時爲全部 host 創建了鏈接並且存了起來,因此這裏只需用 for 循環依次取出,再執行 Connection 的 run() 方法。線程
這裏能夠看到一種很是實用的開發技巧: 建立類時,讓它繼承內置的數據結構(如 list、dict), 這樣能夠直接使用 self.append()、self.extend()、self.update() 等方法把關鍵的信息存到「自身」,再到取出時則「for xxx in self」,這樣就免了建立臨時的 list 或 dict,也省得要在參數中傳來傳去。blog
GroupResult 和 GroupException 是對執行結果和異常的處理,不是咱們關注的重點,這裏略過。
接下來看看 ThreadingGroup,它也只有一個 run() 方法:
ExceptionHandlingThread 是一個繼承了 threading.Thread 的類,這是一種建立多線程的方式。每一個線程執行的方法主要作兩件事:執行 connection 的 run() 方法,以及將執行成功的結果存入隊列中。
接下來再分別把執行成功的結果與出異常的結果都存入到 results 中。
因此,Fabric 是使用了 threading 多線程的方式來實現併發。網絡請求是 IO 密集型的,使用多線程是不錯的方式。
至此,對於咱們在開頭提的問題,就有了一個初步的答案:Fabric 封裝了兩種 Group 來批量管理服務器,其中串行方式就是用了簡單的 for 循環,而併發方式使用了 threading 多線程方式。
可是,經過分析這兩種 Group 的實現代碼(以及使用的實踐),咱們也能夠發現 Fabric 的缺陷:
這幾個問題在 Fabric 的 Github issue 中,被不一樣的人反覆提出,可是尚未獲得很好的迴應……
言歸正傳,本文主要分析了 Fabric 在批量管理服務器時的實現方案,閱讀其源碼,能夠了解到串行/併發典型場景的用法,以及類定義、類繼承、多線程、異常處理等內容,最後,咱們還揭示出了它的幾個特性缺陷。
感謝閱讀。最後,附上 Fabric 教程:https://mp.weixin.qq.com/s/UHtPaxO2ojql5ps4hTn3Vg