本文首發於泊浮目的專欄: https://segmentfault.com/blog...
ZStack是下一代開源的雲計算IaaS(基礎架構即服務)軟件。它主要面向的是將來的智能數據中心,經過提供的API來管理包括計算、存儲和網絡在內的數據中心的各類資源。跟OpenStack相比,ZStack具備易用、穩定、靈活、超高性能等特色。其單管理節點能夠管理1萬臺物理機規模集羣,多個管理節點構建的集羣能夠作到使用一個數據庫、一套消息總線管理10萬臺物理機、數百萬個虛擬機節點、併發處理數萬個API。java
如下是ZStackV2.2的服務架構圖
![]()
官網地址: http://www.zstack.io/核心開源引擎ZStack GitHub:https://github.com/zstackio/z...git
ZStack-Utility GitHub:https://github.com/zstackio/z...github
閱讀源碼若是不想使用IDE,建議配合https://github.com/buunguyen/...。web
本文將對核心引擎-ZStack的源碼進行剖析。在ZStack官網上咱們能夠看到其每一個版本的發佈都是攜帶了許多的新特性。在筆者看來,可以快速迭代的緣由首先是來自於每位工程師的辛勤付出。除此以外,因其還有些軟件工程領域中沉澱下來的最佳實踐:算法
Iaas的核心應該作的是管控層,而不是數據層。故ZStack僅僅也是作出一些「決策」而已——在設計系統的時候,應不考慮在這些決策的執行上消耗大量的資源。在面對大量請求或者「決策」的時候,若是使用多線程來處理阻塞式IO模型時會遇到一些問題:數據庫
而非阻塞、異步的消息驅動系統能夠只運行少許的線程,而且不阻塞這些線程,只在須要計算資源時才使用它們。這大大提升了系統的響應速度,而且可以更高效地利用系統資源。segmentfault
故,ZStack採用了異步架構,分別由三個部分組成:設計模式
若是在系統中的一部分採用異步設計,是不行的。這樣仍是會由於同步而無法享受異步帶來的「福利」。故此整個系統都得采用異步架構。網絡
擴展連接 : ZStack--可拓展性的祕密武器1:異步架構
在ZStack
中,每個服務都是獨立存在的。爲了方便的管理更多的物理機,ZStack
推薦採用集羣部署MN。但這樣就會遇到一個問題,不一樣MN下面有着不一樣的幾個服務存在,在這裏咱們設其爲X個服務。在10個MN部署的狀況下,可能就是10X個服務。那麼在一個資源須要操做時,我須要發送向對應的MN。那麼如何找到那個MN呢?最直觀的想法就是在各個MN中保存相應的「服務表」,這便是一種狀態。那麼在分佈式系統中,採用有狀態的服務絕對不是一個好的選擇,它會嚴重影響系統的擴展性。ZStack
巧妙的採用了一致性哈希算法+MQ解決了這個問題。多線程
擴展連接: ZStack—可拓展性祕密武器2:無狀態的服務
解決併發的問題不必定要用顯式的鎖,也能夠對同一資源作操做的任務作成隊列使其串行執行。
注意:併發 != 並行
擴展連接: ZStack--可拓展性祕密武器3:無鎖架構
在Intellij
中打開ZStack的代碼,會發現大多數目錄底下都會有一個pom.xml
文件,ZStack採用了模塊化項目。模塊化的好處在工程實踐中不言而喻的,好比:
下面來看一下ZStack
中代碼的結構:
截圖於2017.9.22
名稱 | 簡介 |
---|---|
build | 用於Java部分的編譯、打包、部署等 |
conf | 配置文件及SQL文件的放置;Spring Service配置存放;持久化文件配置 |
core | 核心模塊。實現系統的核心功能——包括數據庫、消息總線、工做流實現等等 |
coregroovy | ZStack的最新測試採用了Groovy,這裏是對測試庫作的支持 |
header | 消息以及Entity的定義 |
plugin | 顧名思義。其中很多組件都以插件化開發,提供較高的靈活性 |
sdk | 測試庫使用的SDK |
simulator | 對於測試庫支持的又一模塊,主要用戶simulator agent的行爲 |
testlib | 測試庫 |
test | 測試模塊 |
工具類 | 工具包。目前僅僅支持了doc生成 |
utils | 代碼中使用的工具類 |
其餘 | 功能實現模塊 |
在ZStack
中,每一個功能實現模塊都會被稱爲服務——一個獨立的服務。各個服務之間的通訊由MQ來承擔。這就像是傳統的CSE,C和E是不耦合的,經過S來交互。一樣的,一個服務須要向另外一個服務發起調用,只需往消息總線發送消息,並指定這個服務ID(Service ID)便可。若是某個服務的代碼須要大量重構或者作成微服務,只要提供相同的服務並註冊到MQ上就能夠了。這就是事件驅動架構(Event Driven Architecture)的一種典型實現。
CSE:Controller、Service、Entity。注:稱做Domain或者Model都是不專業的。Domain是一個領域對象,每每咱們再作傳統Java軟件web開發中,這些Domain都是貧血模型,是沒有行爲的,或是沒有足夠的領域模型的行爲的,因此,以這個理論來說,這些Domain都應該是一個普通的entity對象,並不是領域對象,因此請把包名改成:com.xxx.entity。
舉個簡單明瞭的例子。若是每一個對象的行爲都是經過消息來決定的(好比一個方法須要message獲得回覆後才能do something...),那麼這個對象僅僅對消息總線產生了依賴。在測試中,將會發揮巨大的威力——咱們只須要改變handle message處的行爲,就可使一個對象行爲作出相應的變化。這樣可使mock的單位變得更小,同時也能夠變得更加靈活。
試想若是經過函數調用:
//方法a中的代碼 xxService.method1(); xx2Service.method2();
在測試中該如何解耦?但若是經過MQ——即一個消息來調用xxService.method1()
,那麼方法a對xxService就沒有了直接的依賴。
不瞭解Spring的人能夠看: 看起來很長但仍是有用的Spring學習筆記
在代碼中,每當咱們New出一個對象時,這個模塊便對這個對象產生了依賴。當咱們須要測試的時候就不得不去Mock它。當依賴的對象or Field 有成千上萬個的時候,這就是一場災難了。代碼變得愈發不可測,坑就越多,開發者在擴展or維護項目的時候就會愈發的乏力。這就像是咱們以前提到的MQ,服務1->MQ->服務2
,因爲中間隔了一個MQ,因而服務1和服務2沒有必然的關係。一樣的,從對象1->調用->對象2
到對象1->調用->Spring提供的IOC容器->對象2
,這樣使對象與對象之間也沒有了直接調用關係,對象1只要知道它要調用的對象實現了其須要的Interface
就是能夠調用的。
除了Autowired
的正確使用姿式。在ZStack中,還有一類頗有意思的代碼,通常稱之爲xxxExtensionPoint
。其本質就是定義一個接口,而後其實現類做爲Bean經過XML註冊到IOC中。在須要使用的時候,經過Spring獲取到全部實現該接口的對象,調用其函數。這樣就會使代碼變得很是的靈活。
例如,ZStack
分爲多個版本——開源版、企業版、混合雲版等。若是一個服務在不一樣版本中的處理邏輯須要稍許不一樣,那麼就能夠在開源版的代碼中註冊一個接口,在另外一個版本的服務中實現該接口。這樣也不會影響到開源版的原有邏輯。從模塊上看咱們代碼的是鬆耦合而且沒法直接調用的,可是在內存中,倒是能夠調用獲得的。
在ZStack
中
因爲ZStack
源碼作到了必定的解耦合(上述提到)與無狀態,使得集成測試得以進行。
其首席架構師Frank.Zhang曾說過:咱們開發者在寫代碼的時候每每就應該考慮該怎麼寫測試了。想了解ZStack的測試框架,能夠看: ZStack WiKi :管理節點基於模擬器的Integration Test框架
在ZStack
中,設計模式有較爲良好的實踐。筆者有機會將會在以後的系列文章分析其中的典型案例以及在代碼中使用極其頻繁的核心工具。