ZStack源碼剖析:如何在百萬行代碼中快速迭代

本文首發(fā)于泊浮目的專欄:https://segmentfault.com/blog/camile

前言

ZStack是下一代開源的云計算IaaS(基礎(chǔ)架構(gòu)即服務(wù))軟件。它主要面向的是未來的智能數(shù)據(jù)中心佳吞,通過提供的API來管理包括計算徙歼、存儲和網(wǎng)絡(luò)在內(nèi)的數(shù)據(jù)中心的各種資源。跟OpenStack相比款筑,ZStack具有易用轰绵、穩(wěn)定聪铺、靈活扼菠、超高性能等特點摄杂。其單管理節(jié)點可以管理1萬臺物理機規(guī)模集群,多個管理節(jié)點構(gòu)建的集群可以做到使用一個數(shù)據(jù)庫循榆、一套消息總線管理10萬臺物理機析恢、數(shù)百萬個虛擬機節(jié)點、并發(fā)處理數(shù)萬個API秧饮。

以下是ZStackV2.2的服務(wù)架構(gòu)圖


官網(wǎng)地址:http://www.zstack.io/

核心開源引擎ZStack GitHub:https://github.com/zstackio/zstack

ZStack-Utility GitHub:https://github.com/zstackio/zstack-utility

閱讀源碼如果不想使用IDE映挂,建議配合https://github.com/buunguyen/octotree更佳泽篮。

本文將對核心引擎-ZStack的源碼進行剖析。在ZStack官網(wǎng)上我們可以看到其每個版本的發(fā)布都是攜帶了許多的新特性柑船。在筆者看來帽撑,能夠快速迭代的原因首先是來自于每位工程師的辛勤付出。除此之外鞍时,因其還有些軟件工程領(lǐng)域中沉淀下來的最佳實踐:

  • 良好的架構(gòu)設(shè)計
  • 覆蓋較為全面的測試
  • 恰當(dāng)好處的使用設(shè)計模式

良好的架構(gòu)設(shè)計

異步架構(gòu)

Iaas的核心應(yīng)該做的是管控層油狂,而不是數(shù)據(jù)層。故ZStack僅僅也是做出一些“決策”而已——在設(shè)計系統(tǒng)的時候寸癌,應(yīng)不考慮在這些決策的執(zhí)行上消耗大量的資源。在面對大量請求或者“決策”的時候弱贼,如果使用多線程來處理阻塞式IO模型時會遇到一些問題:

  • 阻塞模型的吞吐量受到線程池大小的限制蒸苇;
  • 創(chuàng)建并使用許多線程會耗費額外的時間用于上下文切換,影響系統(tǒng)性能吮旅。

而非阻塞溪烤、異步的消息驅(qū)動系統(tǒng)可以只運行少量的線程,并且不阻塞這些線程庇勃,只在需要計算資源時才使用它們檬嘀。這大大提高了系統(tǒng)的響應(yīng)速度,并且能夠更高效地利用系統(tǒng)資源责嚷。

故鸳兽,ZStack采用了異步架構(gòu),分別由三個部分組成:

  • 異步消息
  • 異步方法
  • 異步HTTP 請求

如果在系統(tǒng)中的一部分采用異步設(shè)計罕拂,是不行的揍异。這樣還是會因為同步而沒法享受異步帶來的“福利”。故此整個系統(tǒng)都得采用異步架構(gòu)爆班。

  • 相對的衷掷,開發(fā)者們在編寫異步代碼的時候得格外小心。
  • 在系統(tǒng)設(shè)計中柿菩,異步調(diào)用可以減少系統(tǒng)在IO上出現(xiàn)瓶頸的可能性戚嗅。

擴展鏈接 : ZStack--可拓展性的秘密武器1:異步架構(gòu)

無狀態(tài)服務(wù)

ZStack中,每一個服務(wù)都是獨立存在的枢舶。為了方便的管理更多的物理機懦胞,ZStack推薦采用集群部署MN。但這樣就會遇到一個問題祟辟,不同MN下面有著不同的幾個服務(wù)存在医瘫,在這里我們設(shè)其為X個服務(wù)。在10個MN部署的情況下旧困,可能就是10X個服務(wù)醇份。那么在一個資源需要操作時稼锅,我需要發(fā)送向?qū)?yīng)的MN。那么如何找到那個MN呢僚纷?最直觀的想法就是在各個MN中保存相應(yīng)的“服務(wù)表”矩距,這即是一種狀態(tài)。那么在分布式系統(tǒng)中怖竭,采用有狀態(tài)的服務(wù)絕對不是一個好的選擇锥债,它會嚴(yán)重影響系統(tǒng)的擴展性。ZStack巧妙的采用了一致性哈希算法+MQ解決了這個問題痊臭。

  • 這在系統(tǒng)設(shè)計中實為是一種使用一致性hash技術(shù)的負(fù)載均衡

擴展鏈接:ZStack—可拓展性秘密武器2:無狀態(tài)的服務(wù)

無鎖架構(gòu)

解決并發(fā)的問題不一定要用顯式的鎖哮肚,也可以對同一資源做操作的任務(wù)做成隊列使其串行執(zhí)行。

注意:并發(fā) != 并行
擴展鏈接:ZStack--可拓展性秘密武器3:無鎖架構(gòu)

松耦合架構(gòu)

項目模塊化

Intellij中打開ZStack的代碼广匙,會發(fā)現(xiàn)大多數(shù)目錄底下都會有一個pom.xml文件允趟,ZStack采用了模塊化項目。模塊化的好處在工程實踐中不言而喻的鸦致,比如:

  • 可以在不影響整個系統(tǒng)的情況下替換某個模塊
  • 開發(fā)者只要專心的在自己的模塊中工作即可
  • 減少系統(tǒng)耦合度潮剪,提高內(nèi)聚,減少資源循環(huán)依賴分唾,增強系統(tǒng)框架設(shè)計
  • ...

下面來看一下ZStack中代碼的結(jié)構(gòu):

代碼結(jié)構(gòu)

截圖于2017.9.22

名稱 簡介
build 用于Java部分的編譯抗碰、打包、部署等
conf 配置文件及SQL文件的放置;Spring Service配置存放;持久化文件配置
core 核心模塊绽乔。實現(xiàn)系統(tǒng)的核心功能——包括數(shù)據(jù)庫弧蝇、消息總線、工作流實現(xiàn)等等
coregroovy ZStack的最新測試采用了Groovy折砸,這里是對測試庫做的支持
header 消息以及Entity的定義
plugin 顧名思義捍壤。其中不少組件都以插件化開發(fā),提供較高的靈活性
sdk 測試庫使用的SDK
simulator 對于測試庫支持的又一模塊鞍爱,主要用戶simulator agent的行為
testlib 測試庫
test 測試模塊
工具類 工具包鹃觉。目前僅僅支持了doc生成
utils 代碼中使用的工具類
其他 功能實現(xiàn)模塊

通過MQ來解耦合

ZStack中,每個功能實現(xiàn)模塊都會被稱為服務(wù)——一個獨立的服務(wù)睹逃。各個服務(wù)之間的通信由MQ來承擔(dān)盗扇。這就像是傳統(tǒng)的CSE,C和E是不耦合的沉填,通過S來交互疗隶。同樣的,一個服務(wù)需要向另一個服務(wù)發(fā)起調(diào)用翼闹,只需往消息總線發(fā)送消息斑鼻,并指定這個服務(wù)ID(Service ID)即可。如果某個服務(wù)的代碼需要大量重構(gòu)或者做成微服務(wù)猎荠,只要提供相同的服務(wù)并注冊到MQ上就可以了坚弱。這就是事件驅(qū)動架構(gòu)(Event Driven Architecture)的一種典型實現(xiàn)蜀备。

CSE:Controller、Service荒叶、Entity碾阁。注:稱作Domain或者Model都是不專業(yè)的。Domain是一個領(lǐng)域?qū)ο笮╅梗覀冊僮鰝鹘y(tǒng)Java軟件web開發(fā)中脂凶,這些Domain都是貧血模型,是沒有行為的愁茁,或是沒有足夠的領(lǐng)域模型的行為的烁峭,所以良姆,以這個理論來講因悲,這些Domain都應(yīng)該是一個普通的entity對象煞肾,并非領(lǐng)域?qū)ο螅哉埌寻臑?com.xxx.entity道宅。

舉個簡單明了的例子。如果每個對象的行為都是通過消息來決定的(比如一個方法需要message得到回復(fù)后才能do something...)胸蛛,那么這個對象僅僅對消息總線產(chǎn)生了依賴污茵。在測試中,將會發(fā)揮巨大的威力——我們只需要改變handle message處的行為葬项,就可以使一個對象行為做出相應(yīng)的變化泞当。這樣可以使mock的單位變得更小,同時也可以變得更加靈活民珍。

試想如果通過函數(shù)調(diào)用:

//方法a中的代碼
xxService.method1();
xx2Service.method2();

在測試中該如何解耦襟士?但如果通過MQ——即一個消息來調(diào)用xxService.method1(),那么方法a對xxService就沒有了直接的依賴嚷量。

使用Spring

不了解Spring的人可以看:看起來很長但還是有用的Spring學(xué)習(xí)筆記

在代碼中陋桂,每當(dāng)我們New出一個對象時,這個模塊便對這個對象產(chǎn)生了依賴蝶溶。當(dāng)我們需要測試的時候就不得不去Mock它嗜历。當(dāng)依賴的對象or Field 有成千上萬個的時候,這就是一場災(zāi)難了抖所。代碼變得愈發(fā)不可測梨州,坑就越多,開發(fā)者在擴展or維護項目的時候就會愈發(fā)的乏力田轧。這就像是我們之前提到的MQ暴匠,服務(wù)1->MQ->服務(wù)2,由于中間隔了一個MQ傻粘,于是服務(wù)1和服務(wù)2沒有必然的關(guān)系每窖。同樣的帮掉,從對象1->調(diào)用->對象2對象1->調(diào)用->Spring提供的IOC容器->對象2,這樣使對象與對象之間也沒有了直接調(diào)用關(guān)系岛请,對象1只要知道它要調(diào)用的對象實現(xiàn)了其需要的Interface就是可以調(diào)用的旭寿。

除了Autowired的正確使用姿勢。在ZStack中崇败,還有一類很有意思的代碼盅称,一般稱之為xxxExtensionPoint。其本質(zhì)就是定義一個接口后室,然后其實現(xiàn)類作為Bean通過XML注冊到IOC中缩膝。在需要使用的時候,通過Spring獲取到所有實現(xiàn)該接口的對象岸霹,調(diào)用其函數(shù)疾层。這樣就會使代碼變得非常的靈活。

例如贡避,ZStack分為多個版本——開源版痛黎、企業(yè)版、混合云版等刮吧。如果一個服務(wù)在不同版本中的處理邏輯需要稍許不同湖饱,那么就可以在開源版的代碼中注冊一個接口,在另一個版本的服務(wù)中實現(xiàn)該接口杀捻。這樣也不會影響到開源版的原有邏輯井厌。從模塊上看我們代碼的是松耦合并且無法直接調(diào)用的,但是在內(nèi)存中致讥,卻是可以調(diào)用得到的仅仆。

覆蓋較為全面的測試

ZStack

  • 開發(fā)者Fix每一個Bug都是需要補充相應(yīng)的Case;
  • 每一個Feature在進去之前更會由開發(fā)工程師與QA工程師同時制定測試場景并Cover垢袱;
  • 每一個PR(pull request)進去之前都會通過PR系統(tǒng)跑過所有的Case墓拜,以防止Bug的Regression;

由于ZStack源碼做到了一定的解耦合(上述提到)與無狀態(tài)请契,使得集成測試得以進行撮弧。

其首席架構(gòu)師Frank.Zhang曾說過:我們開發(fā)者在寫代碼的時候往往就應(yīng)該考慮該怎么寫測試了。

想了解ZStack的測試框架姚糊,可以看: ZStack WiKi :管理節(jié)點基于模擬器的Integration Test框架

恰當(dāng)好處的使用設(shè)計模式

ZStack中贿衍,設(shè)計模式有較為良好的實踐。筆者有機會將會在之后的系列文章分析其中的典型案例以及在代碼中使用極其頻繁的核心工具救恨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贸辈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌擎淤,老刑警劉巖奢啥,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嘴拢,居然都是意外死亡桩盲,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門席吴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赌结,“玉大人,你說我怎么就攤上這事孝冒〖硪Γ” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵庄涡,是天一觀的道長量承。 經(jīng)常有香客問我,道長穴店,這世上最難降的妖魔是什么撕捍? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮泣洞,結(jié)果婚禮上忧风,老公的妹妹穿的比我還像新娘。我一直安慰自己斜棚,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布该窗。 她就那樣靜靜地躺著弟蚀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酗失。 梳的紋絲不亂的頭發(fā)上义钉,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機與錄音规肴,去河邊找鬼捶闸。 笑死,一個胖子當(dāng)著我的面吹牛拖刃,可吹牛的內(nèi)容都是我干的删壮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼兑牡,長吁一口氣:“原來是場噩夢啊……” “哼央碟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起均函,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤亿虽,失蹤者是張志新(化名)和其女友劉穎菱涤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洛勉,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡粘秆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了收毫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攻走。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖牛哺,靈堂內(nèi)的尸體忽然破棺而出陋气,到底是詐尸還是另有隱情,我是刑警寧澤引润,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布巩趁,位于F島的核電站,受9級特大地震影響淳附,放射性物質(zhì)發(fā)生泄漏议慰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一奴曙、第九天 我趴在偏房一處隱蔽的房頂上張望别凹。 院中可真熱鬧,春花似錦洽糟、人聲如沸炉菲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拍霜。三九已至,卻和暖如春薪介,著一層夾襖步出監(jiān)牢的瞬間祠饺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工汁政, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留道偷,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓记劈,卻偏偏與公主長得像勺鸦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子目木,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354