架構現代化-微服務
Hi,我是阿昌
,今天學習記錄的是關于架構現代化-微服務
的內容。
在自治氣泡模式
的基礎上,通過事件攔截
來實現數據同步
,給氣泡和遺留系統之間又加上 API 訪問
這個通信渠道。
這時的自治氣泡就和真正的微服務差不多了。
有了這種模式,在開發(fā)一個全新的需求時,你就可以將新需求實現在新的服務中,通過防腐層和遺留系統隔離,達到自治的目的。
這樣,新服務可以更好地演進,不受遺留系統的影響;
遺留系統也不會因為新需求的增加而帶來太多修改。
然而,單體真的不好嗎?微服務一定是目標架構嗎?
一、單體和微服務應該如何取舍?
這個問題眾說紛紜,幾個有代表性的咱們看看。
-
在 2015 年,Martin Fowler 就撰文強調,即使知道系統會大到值得去使用微服務,也應該單體先行;
-
Stefan Tilkov 卻說如果目標是一個微服務架構,就不要從單體開始;
-
C4 模型的作者 Simon Brown 的觀點則是,如果連單體都構建不好,憑什么認為微服務就是想找的答案呢?
-
最“氣人”的就是《微服務設計》的作者 Sam Newman,在被問到應該何時使用微服務時,他的回答是:應該在有足夠理由的時候。
大牛們的觀點要么針鋒相對,要么似是而非,那到底應該如何取舍呢?
直到有一天,在網上看到一條視頻,是 Matthew Skelton 和 Manuel Pais 在倫敦一個技術大會上的演講,題目是:Monoliths vs Microservices is Missing the Point—Start with Team Cognitive Load。單體有單體的好處,微服務也有微服務的好處。
同時,選擇了任何一種,也都要面對它所帶來的問題。所以,單純從純技術角度說哪個好,是沒有意義的。同樣是微服務,有些團隊如虎添翼,有些團隊卻步履蹣跚。這一切的背后并不是技術本身在搞怪,而是人,是團隊的認知負載。Martin Fowler 和 Sam Newman 們無法用語言表達出來的模棱兩可,被如此輕描淡寫地化解。就仿佛一個置身四維空間的神,在低頭嘲笑三維空間中渺小的人類。這是一個徹徹底底的降維打擊。也就是說,判斷依據不應該是技術本身,而應該是團隊的認知負載。
哪一種方案對當前團隊來說認知負載低,哪一種就更有可能成功。比如一個包含 10 個模塊的單體系統,目前共有 10 個開發(fā)人員,如果按模塊拆分成微服務,平均每個人要維護一個服務,這就超出了人的認知負載。
正確的方案可能要這樣演進:先拆出一個不太大的服務,抽出 2 到 3 名開發(fā)人員組成新的團隊來維護它,然后再慢慢擴張團隊,并逐漸拆出新的服務,直到形成一個 5 到 9 人的團隊維護一個服務這樣的比例為止。
二、單體向微服務的演進
在確定了要拆分之后,應該如何演進。
1、大泥球單體架構
單體架構往往都是“大泥球”(Big Ball of Mud),這也是遺留系統最常見的情況。
大泥球架構可能也分一些層次,如常見的三層或四層結構。
但它的內部就不忍直視了,特別是業(yè)務邏輯層內部,各個模塊的邊界十分模糊,往往是你調用我,我調用它,它又調用你,循環(huán)往復,錯綜復雜;持久層也好不到哪去,本應屬于不同模塊的表之間 join 來 join 去,形成一張大網。
大泥球并不是一種架構風格,也沒有人一開始就想構建一個這樣的架構,它們只是從簡單的分層架構中逐漸腐化而成的。
對于小型的、簡單的軟件來說,選擇分層架構沒什么不好。
只是隨著業(yè)務的演進,架構沒有得到很好地守護,才一步步變成了大泥球。
2、基于組件的單體架構
要想改善大泥球架構,最重要的就是把業(yè)務模塊之間的耦合解開,消除掉模塊間的相互依賴關系。
同時,也要將數據的所有權分開,讓不同的模塊擁有不同的數據。
這種類型的單體架構稱之為基于組件的單體架構
。
當然,要達到這樣的理想情況實際很難。因為一個模塊想不依賴另一個模塊的數據,這不太可能。
比如銷售模塊不可能不依賴庫存數據。在大泥球中的做法,當然是在銷售模塊中直接訪問庫存表,但在基于組件的單體架構中,要讓庫存模塊提供一個外部模塊可以訪問的接口(非 Web API),銷售模塊通過防腐層去調用這個接口,轉換成銷售業(yè)務所需要的庫存數據。
這樣,銷售模塊就不再直接依賴庫存數據表了。這種模塊之間雖然也有依賴,但比起銷售模塊依賴庫存模塊的庫存對象來說,還是要好出不少的。它通過防腐層對不同模塊進行了隔離,一個模塊中模型的修改,不會影響到另一個模塊。
如果大泥球的模塊之間比較好解耦,就可以先將其中一個模塊解耦出來,再逐步把其他模塊也一一照方抓藥。
如果沒有系統彈性等方面的非功能需求,那么基于組件的單體架構,就是一個比較理想的架構形態(tài)了。
常常用“分而不拆”來形容這種架構風格。
3、基于服務的分布式架構
當單體內的模塊清晰之后,會發(fā)現一些模塊描述的是一個大的業(yè)務領域,你可以嘗試按業(yè)務領域給這些模塊分組,將它們拆分出來,形成服務。這種架構叫做基于服務的分布式架構
。
Mark Richards 和 Neal Ford 在《軟件架構:架構模式、特征及實踐指南》這本書中詳細介紹了這種架構。
相對微服務而言,這時的服務是粗粒度的,Neal 管它叫做領域服務,要注意這里的領域服務概念,它和 DDD 中的領域服務并不一樣。
這里的領域服務是指,由描述同一塊業(yè)務領域的多個模塊所組成的服務。比如保險行業(yè)的理賠是一個業(yè)務領域,它可能由報案、受理、理算、結案等多個模塊組成。
這些服務往往都只有一個用戶界面層和數據庫。當然,如果數據庫成為瓶頸的話,也有可能需要對數據庫進行拆分
基于服務的分布式架構既可以作為一個過渡架構,也可以作為目標架構。
它是一種粗粒度的微服務架構,每個服務都可以獨立部署,并包含一個特定領域的所有業(yè)務邏輯。
可以自行決定哪些領域需要進一步細化,哪些保持粗粒度就足夠滿足需求了。這種過渡架構優(yōu)勢是什么?
一方面,這種架構享受了一部分可擴展性
和高可用性
,這是分布式架構帶來的“增益 buff”。同時,由于服務數量并不會很多,也不會像微服務架構那樣,帶來太多的系統復雜性和運維負擔。
有意思的是,很多項目號稱做到了微服務架構,其實質上只是這種基于服務的分布式架構而已。
4、微服務架構
如果基于服務的分布式架構仍然無法滿足需求,比如同一服務中,不同模塊之間彈性需求的差異越來越大,那就不得不對模塊繼續(xù)拆分。
比如理賠領域中的報案模塊,需要 7x24 小時的高可用服務,以支撐客戶的自助報案。
但其他模塊則沒有這種需求。當各個模塊及其數據庫的彈性邊界都不同時,就拆分出了微服務架構
。
在微服務架構下,業(yè)務邊界變得十分清晰,每個服務可以獨立部署和演進,并且可以選擇不同的技術棧。一個團隊只負責一個或少量的服務(業(yè)務模塊),可以更好地守護住這個服務不被外界腐化。同時由于關注點比較聚焦,認知負載也得到了降低。
很多人覺得不同技術棧這一點并沒有多吸引人,可能是因為并沒有看到適用場景,反而是有些人盲目地引入多語言,用不同編程語言去開發(fā)相似的業(yè)務,憑空增加了很多認知負載。
多語言開發(fā)是指讓不同的語言去處理各自擅長的領域,比如用 Python 去處理算法,用 Scala 去處理數據。但如果沒有特殊需求,只是憑喜好來混合使用多種技術棧,那簡直就是多此一舉。
微服務架構雖然降低了開發(fā)人員的認知負載,但卻提升了運維人員的認知負載。它實際上是用運維復雜度來置換開發(fā)復雜度。開發(fā)人員所面對的內容少了,更加聚焦了,但運維人員卻從以前運維一個單體服務,變?yōu)檫\維幾個甚至幾十個上百個微服務。這需要強有力的 DevOps 文化作為支撐。
所以,如果團隊不具備這樣的能力和文化,最好不要引入微服務。
把那種無視團隊認知負載,只因為技術先進性而盲目拆分微服務的行為,叫做微服務強迫癥(Microservice Envy)。
三、遺留系統的架構應該如何演進?
剛才說了很多種架構風格,那到底什么樣的架構適合遺留系統呢?
如果系統目前是一個大泥球單體架構,且已經明確體現出一些問題,比如代碼越來越混亂,那就要考慮改進架構了。
Neal Ford 在他的新書《Software Architecture: The Hard Parts》中提出了一個架構解耦的決策樹,非常適合輔助來決定采取什么策略應對遺留系統的架構。
從這個決策樹中可以看出,首先需要判斷,系統是否適合進行模塊化?
如果不適合,就保留單體架構不動。那如何判斷是否適合呢?
Neal 給出了一些模塊化的驅動因素:
可以從可用性、可擴展性、可部署性、可測試性、可維護性幾個方面來判斷。
如果系統對這些指標有著比較高的要求,就是適合模塊化的;如果并不關心,就可以保留單體結構不變。
不過,恐怕很少有系統會不關心這些指標吧。如果系統適合模塊化,下一步還要判斷代碼庫是否可拆分,也就是是否有可能把一個大泥球代碼庫拆分成多個小的代碼庫。
Neal 在書中給出了三種代碼的特征指標來輔助我們判斷,分別是:傳入傳出耦合(Afferent and Efferent Coupling)、抽象性和不穩(wěn)定性,以及和主序列的距離。
如果代碼庫可拆分,下一步就是判斷系統的各個模塊之間是否具有清晰的組件邊界。
如果有,就可以選擇基于組件的分解(Compnent-based Decomposition)模式,否則可以使用戰(zhàn)術分叉(Tactical Forking)模式。
四、基于組件的分解
基于組件的分解模式適合將單體架構遷移到基于服務的分布式架構上,這往往是我們邁向微服務架構的第一步。
如果目前的系統是基于組件的單體架構,輕而易舉就能使用這種模式。但如果系統仍然是大泥球,但是組件邊界相對來說還算比較清晰,也可以使用這種模式。
Neal 在《Software Architecture: The Hard Parts》中介紹了 6 種組件分解模式,簡單給盤點一下:
- 識別和調整組件大?。航y計各個模塊的代碼語句數,拆分那些過于龐大的組件,使所有組件的語句數趨于一致。
- 收集公共領域組件:在基于組件的單體架構中,很多組件的功能是類似的,比如郵件通知和短信通知,或者訂單通知模塊和物流通知模塊。識別這些模塊并進行合并,有助于消除重復。
- 展平組件:讓組件中的類都位于葉子節(jié)點的包中,不要出現孤兒類(即類和其他包平級)。
- 明確組件依賴:分析組件之間的依賴關系。
- 構建領域組件:在邏輯上將屬于同一領域的組件組合在一起。
- 創(chuàng)建領域服務:當組件的大小適中、結構扁平,并且按領域分組后,就可以在此基礎上拆分出領域服務,構建基于服務的分布式架構了。
需要引起注意的是,在微服務或基于服務的分布式架構中,它們的服務都是這種按組件或領域組件來劃分的,它們描述的是業(yè)務而不是數據。
很多架構師在設計服務的時候,不是按業(yè)務劃分,而是按比較復雜的實體對象來劃分。比如員工服務或商品服務,就只包含員工或商品的增刪查改。這樣的服務稱之為實體服務(Entity Service),是一種典型的反模式。
要完成一個簡單的業(yè)務場景,需要有一個編排服務來編排多個實體服務,這導致業(yè)務邏輯位于編排服務中,而不是微服務中;
一個常見的業(yè)務需求,都可能會涉及多個實體服務的修改,這就導致服務無法獨立部署,只能多個服務或整體一起部署。
這樣一來,就跟單體架構沒有區(qū)別了,甚至更糟,因為它還是分布式的。管這種架構叫做分布式單體
(Distributed Monolith)。
遺憾的是,網上很多微服務的示例,包括Spring 和微軟的示例,其實都是分布式單體。
當然,它們主要是想描述如何搭建和運維一個服務,但要長個心眼兒,千萬不要以為這樣的服務就是微服務的樣板,并且盲目效仿。
五、戰(zhàn)術分叉
如果一個大泥球單體架構中,連相對清晰的組件邊界都沒有,所有代碼混在一起,這種情況拆分起來會十分困難。
通常來說,當我們考慮從一個大的整體中,把一個小的部分挪出去的時候,方法都是“拆”。但當“拆”不動的時候,你可以變換一下思路,用“刪”的方式來實現拆分。這種模式,就叫做戰(zhàn)術分叉
。
怎么刪呢?先把系統整體復制一份,然后在復制出來的系統中刪掉不需要的代碼,保留下來的就是希望拆分出來的部分了。
在系統之上,需要構建一個反向代理
,根據請求來判斷,需要轉發(fā)給原來的系統,還是復制出來的分叉系統。
在使用戰(zhàn)術分叉之前,需要先對大泥球加以梳理。盡管代碼可能無法體現出很好的模塊化,但業(yè)務領域還是有邊界的。
可以使用服務藍圖、用戶故事地圖等工具,來識別企業(yè)的業(yè)務領域,然后選擇一個希望“分叉”出去的業(yè)務能力。
在實際操作中,發(fā)現這種模式非常有用。因為很少有系統能夠做到真正的模塊化,更多的遺留系統現狀是,有大體的業(yè)務模塊,但從代碼層面上看,模塊之間耦合過于嚴重,很難通過基于組件的分解模式來拆分。
采用戰(zhàn)術分叉時,開發(fā)團隊可以立即開始工作,不需要事先做太多的分析。而且在開發(fā)人員看來,刪代碼總是比提取代碼要容易得多。
但這也會導致兩邊的系統或服務都不可能刪得太干凈,相當于從一個大泥球中剔出來一個小泥球,等服務可以獨立部署之后,還是會有很多善后工作要做。
六、總結
如何選擇遺留系統的目標架構,到底是單體合適,還是微服務合適呢?看起來“二選一”的題目,還有更適合自己業(yè)務的隱藏選擇么?
拆與不拆,要看認知負載。拆成什么樣,要按步驟演進。除了微服務,基于組件的單體架構和基于服務的分布式架構也有可能是大泥球單體的最終目標,如何取舍主要還是看業(yè)務上是否具有彈性需求。在拆分時,你可以使用基于組件的分解
和戰(zhàn)術分叉
兩種模式。
微服務是個非常龐大的話題,很難在一節(jié)課中體現所有內容。奉勸你一句,拆分微服務一定要想清楚為什么要拆
。
邏輯上分離(分)和在邏輯分離的基礎上再做物理上隔離(拆)是兩件事,解決的也是兩個問題。
前一個解決的是知識邊界封裝和解耦的問題,后一個是想要物理隔離后的一些優(yōu)勢(如技術異構、彈性邊界、可用性隔離、安全分級隔離、服務級別的獨立交付等)。文章來源:http://www.zghlxwxcb.cn/news/detail-434780.html
大部分的拆分都承擔了后者的成本,但是做的是前者的事兒,沒享受到后者的好處。文章來源地址http://www.zghlxwxcb.cn/news/detail-434780.html
到了這里,關于Day960.架構現代化-微服務 -遺留系統現代化實戰(zhàn)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!