吳佳驊
(武漢城市職業學院 湖北·武漢 430064)
現在的項目開發早已不是平地起樓式的了。虛擬機、運行時、編譯器、中間件、開發框架、數據庫以及其他各種要配置的環境,在項目開發之前,以上這些都得先準備好,否則大概率影響實際開發任務完成進度。然而,這種由各種雜七雜八的東西形成的龐雜集合體,本身在部署時就很讓人費神,稍有不慎,可能就會導致環境錯誤,在部署中發生人為錯誤的概率不低。當項目中發生新應用的加入時,也時常需要添加其他環境組件。這些原項目來說,有時就像是入侵的細菌,可能導致項目崩潰。于是,解決這些附加組件帶來的麻煩又成了不小的工作量。這些原本與開發任務本身關系不大的工作,需要在項目的各個階段上重復執行,消耗大量的精力和耐性,對于要求速度的項目開發,顯然很不劃算。
于是,容器技術開始被應用在項目開發當中。這是一種能夠把環境變量、應用、數據庫等等打包在一個封閉的鏡像當中的技術,當需要調用它們的時候,只需要根據鏡像去生成具體的執行實例。不同的實例里可以包含不同的組件來提供服務,而實例與實例之間是彼此獨立的。容器的出現使開發人員能用更靈活的方式去組織所需要的復雜環境。因為實例與實例之間彼此互不干涉,由不同組件代碼或者執行庫沖突和不兼容等問題所引起的各種錯誤也就很難出現了。開發人員可以將全部的精力集中在項目本身的開發業務上,整體的開發效率提高了。
不過,把組件裝進籠子里的容器技術,是否真的是解決問題的銀色子彈?與傳統方式相比,在從雜亂環境部署的魔障里解救出開發人員的同時,作為代價是否又失去了什么,比如性能?為了解開這個疑問,用開發項目常用的NoSQL數據庫MongoDB做代表,測試比較物理機部署和容器部署的性能表現。
MongoDB使用C++語言編寫,是一種面向文件存儲的分布式NoSQL數據庫。MongoDB會把數據當作文檔來存放,風格和JSON很像,數據結構是鍵值對,值又可以再包含別的文檔、列表或者文檔的列表。整體使用風格都比較像關系數據庫,操作也比較簡單。
Docker在容器中最流行,它用Go語言編寫,并用appche2.0許可證開源,英文意思是碼頭工人搬運的箱子。正如其名,Docker所提供的容器就像是一個一個的箱子,箱子里裝著各種各樣的東西,箱子與箱子直接又彼此獨立,每個箱子同時又呈現類似的可以相互堆疊的規格,很容易組合。Docker由四個部分組成:客戶端、守護進程、鏡像和容器。Docker的運作方式是C/S模式。守護進程充當后臺服務器,負責接受請求,并且處理它們。客戶端則提供人機交互界面,讓用戶可以和守護進程進行交互活動。客戶端和守護進程可以被部署在同一臺主機上,開發用計算機大都如此;也可以分開來部署成遠程模式,通過socket來完成通信。鏡像是Docker由需要的環境變量、運行庫和其他組件一起通過打包生成的模板,容器是鏡像的實現,一份鏡像可以實現無數相同的容器。
為了測試結果更有參考價值,測試環境使用兩套完全一樣的硬件和操作系統。硬件:處理器intelcorei5-9400F,主頻2.9GHz;硬盤SSD;內存16G DDR4。以上勝任一般開發用計算機,SSD可降低I/O對測試結果的影響。操作系統ubuntu16.04LTS,Docker版本17.03.1,MongoDB版本5.0.2。計算機A直接安裝MongoDB,計算機B建立MongoDB的Docker鏡像然后生成Docker容器。
為了貼近平時的開發情景,本次測試分為兩項:針對只讀性能的測試和針對讀寫混合操作性能的測試。只讀的性能測試設定為請求次數為25萬次,數據量100萬,表數30張,列數10列。讀寫混合操作的性能測試設定為請求次數25萬次,數據量100萬,表數1張,列數10列。
每種測試都設置4種并發線程:10線程、32線程、64線程、128線程。測試框架選擇使用業內流行的sysbench-MongoDB。測試的數據全部在當次測試之前隨機生成,避免數據庫緩存對測試結果造成的影響。測試結果以獲得的每秒鐘完成事務數量為準,即TPS。
四輪只讀性能測試的TPS結果如圖1所示。

圖1:只讀性能TPS
從圖1中不難看出,直接物理機安裝MongoDB的計算機A與使用Docker部署MongoDB的計算機B在只讀性能上還是有些差異的。10線程測試中,計算機A和B的實測TPS數據分別是400和399,基本持平。32線程測試中,計算機A和B的實測TPS數據分別是410和360,計算機B比A性能大約低12%。64線程測試中,計算機A和B的實測TPS數據分別是395和385,計算機B比A性能大約低3%。128線程測試中,計算機A和B的實測TPS數據分別是405和396,計算機B比A性能上大約低3%。兩者的最大性能差發生在32線程測試中。
通過以上數據分析,可以認為使用Docker部署MongoDB的計算機B在只讀性能上要稍遜于直接物理機安裝MongoDB的計算機A,最大性能差距在中線程體現得較為明顯,而在低線程和高線程并不會在性能上拉開較大的差距。
四輪讀寫混合操作性能測試的TPS結果如圖2所示。

圖2:讀寫混合操作性能TPS
從圖2中可以看出,二者在讀寫混合操作性能上同樣存在差異。10線程測試中,計算機A和B的實測TPS數據分別是175和155,計算機B比A性能上大約低11%。32線程測試中,計算機A和B的實測TPS數據分別是200和167,計算機B比A性能上大約低16%。64線程測試中,計算機A和B的實測TPS數據分別是195和185,計算機B比A性能大約低5%。128線程測試中,計算機A和B的實測TPS數據分別是199和188,計算機B比A性能大約低1%。兩者的最大性能差依舊發生在32線程測試中。
通過以上數據分析,可以認為使用Docker部署MongoDB的計算機B在讀寫混合操作性能上要明顯遜于直接物理機安裝MongoDB的計算機A,最大性能差發生在中線程,甚至高達15%以上,在低線程的性能差也在10%以上,在中高線程和高線程兩者勉強保持5%以內的性能差距。
同時,對比圖1和圖2的結果,不難看出,兩者的性能差距在讀寫混合操作時明顯大于只讀時。
通過在相同硬件條件下對只讀和讀寫混合操作這兩種性能共8輪測試的結果分析,不難看出將MongoDB部署在Docker中雖然并不能在性能上完全與傳統的物理機部署持平,但是損失的性能代價并不算太大,在低線程和高線程情況下這種性能差距是可以勉強接受,而在開發過程中最常涉及到中線程的情況下性能差距較大甚至超過10%。
所以,對于完全解決開發流程各個階段上復雜煩瑣的環境部署以保障整個流程里的環境一致這一問題,Docker并非銀色子彈。在性能和便利的天平上,還是得依靠開發團隊去針對實際的需求做出增減砝碼的取舍。