重新理解微服務之終究繞不過這4個坎?(觀點探討)
系列文章
- .Net微服務實戰(zhàn)之技術(shù)選型篇
- .Net微服務實戰(zhàn)之技術(shù)架構(gòu)分層篇
- .Net微服務實戰(zhàn)之DevOps篇
- .Net微服務實戰(zhàn)之負載均衡(上)
- .Net微服務實戰(zhàn)之CI/CD
- .Net微服務實戰(zhàn)之Kubernetes的搭建與使用
- .Net微服務實戰(zhàn)之負載均衡(下)
- .Net微服務實戰(zhàn)之必須得面對的分布式問題
- .Net微服務實戰(zhàn)之可觀測性
- 重新理解微服務之它還那么純粹嗎?
前言
本文于 2022.6.29,首發(fā)于ITPUB 官方公眾號,作者陳珙,未經(jīng)授權(quán)禁止轉(zhuǎn)載。如需轉(zhuǎn)載,請聯(lián)系 ITPUB 公眾號。
上星期,我發(fā)了篇文章——《重新理解微服務之它還那么純粹嗎?》,從微服務從他的過去、本質(zhì)出發(fā)跟大家分享自己一些見解。此篇文章會從4個爭議比較多的微服務話題出發(fā),再跟大家再分享一二。
原本兩篇文章是以一篇來寫的,但是原字數(shù)1萬7千多字,經(jīng)過和DTCC的韓老師溝通后,最終拆成了兩部分。
寫在前頭
大家曾經(jīng)有沒有遇過日常技術(shù)交流的時候,會討論某某技術(shù)之間的關(guān)系是什么,某些技術(shù)是否應該用到微服務。我相信熱愛技術(shù)交流的您,就算不是在微服務這里領(lǐng)域,或多或少都會跟其他同行會做一些爭議話題的探討,而且我敢肯定這些討論絕對熱火朝天。
今天我想從微服務的4個比較火熱的話題進行出發(fā),與大家分享我對微服務的一些個人見解,這4個話題分別是:微服務來帶的新問題、微服務與SOA、微服務與DDD、是否有必要引入聚合層。這里部分話題,在業(yè)界會存在一定的爭議性,例如DDD的引入、微服務與SOA的關(guān)系。
一千個人眼中有一千個哈姆雷特,不同的人以不同的視角去看待這些問題,都會擁有不同觀點與答案。觀點上,咱們求同存異,不盲目遵從別人的想法,也不自以為是的把自己當成標準。
當然了,我并不會為了個人見解而故意制造觀點與話題,更不會把我所有的觀點當成一個“所謂的”標準。因此在該篇文章,我會把多處理收集的資料梳理好放到文內(nèi),有理有據(jù)地結(jié)合自己的見解與大家分享一二。
這些內(nèi)容可能是大家日常容易混淆的,也可能是大家多次糾結(jié)不知道如何做出選擇,因此我希望通過我該篇文章的分享,能給大家?guī)硇碌挠^點上的碰撞,或是見解上的共鳴。
微服務帶來的新問題
做技術(shù)選型就如網(wǎng)上購物一樣,即使知道了它的優(yōu)點,還得看看它的差評。我們得多方面評估,事先知道團隊與業(yè)務是否能抵御與承受“坑”的風險。
既然任何一樣技術(shù)都無法成為軟件工程的銀彈,那么必然解決了某種問題的同時,也會帶來一些新問題,微服務也不例外。我回顧了下當時我實施時的難點確實有不少。不過,我個人認為微服務給我們帶來最核心的問題主要有三點,兩文化與一思維:
- 自動化文化
- 可觀測性文化
- 分布式系統(tǒng)思維

上面這三個問題,每個的內(nèi)容單獨拿來出講的篇幅,都足以出一篇完整的文章甚至是書,基于此我會挑一些重點和大家分享。當然,幾乎每部分的文末,我會放入相關(guān)內(nèi)容的文章外鏈,如果大家有興趣可以自行擴展閱讀。
自動化:避免重復的人力勞動
任何的架構(gòu)模式,也是需要同等的開發(fā)模式與之配合的,隨著應用的拆分后服務的數(shù)量由量變引起質(zhì)變,因而需要接受自動化來代替從前的“人工處理”,包括服務的部署、服務注冊發(fā)現(xiàn)等等。自動化,是軟件工程的其中一種處理手段,允許團隊采用主流的工具、流程形成一套自動化機制,從而減少重復性工作、減少人力干預的不確定性因素。
這里說說我對軟件工程的理解:通過多人協(xié)作、有目標、有步驟、有計劃的,并使用科學方法論指導開發(fā)與維護程序的這個過程,也可以換成一條公式表達:軟件工程 = 工具 + 流程 + 模式。

無論是我們討論的這些“事”、技術(shù)工具,還是流程制度都是需要人(團隊組織)的參與,人的延申就是團隊與文化,就如上述所說的軟件工程是多人協(xié)作的工作,只有當然團隊目標一致,共同負責承擔團隊的項目,共同接受同一種文化才能很好的實施自動化。
我簡單舉個例子:如同多匹馬拉車一樣,只有它們都有共同的目標的時候,才能快速拉車到目的,如果它們一匹向東一匹西,只會讓馬車無法前行甚至四分五裂。
說到這里有些人覺得疑惑,自動化這種能給團隊省時省力、減少重復工作量、增加幸福度的技術(shù)難道還有人或者團隊會抗拒的?是的,還真的有。
我曾經(jīng)就接觸過幾個團隊的Leader,他們的團隊都是推行自動化失敗了,失敗的原因就在于成員不配合,成員拒絕配合的理由是:沒有自己親手去做總覺得機器不靠譜。我們先忽略他們的想法是對是錯,回到團隊與文化,從上面可知,統(tǒng)一團隊的目標一致性是有必要的,作為技術(shù)領(lǐng)導者推行優(yōu)良的方案,是我們的職責之一。如果團隊成員無法配合,導致推行受阻,我們一共有三種應對策略:激勵、考核和逐步試行。

如果有條件的公司可以設置獎金激勵,如果有績效考核的,可以將自動化的實施納入考核目標,如果這倆都沒有,那就選取團隊里愿意改變的同事牽頭試行,假如使用過后都說好,那么會更有說服力?!?/span>
這部分就說到這里吧,基于此話題的內(nèi)容比較多,廣而泛,篇幅有限,這里分享一篇我自己曾分享過的內(nèi)容《.Net微服務實戰(zhàn)之DevOps篇》,如有感興趣的朋友,可看完整篇文章后自行有選擇性、針對性地擴展閱讀。
可觀測性:提高團隊對系統(tǒng)運作的信息量
如果說自動化是給團隊帶來穩(wěn)定性,減輕工作量的,那么可觀測性就是提高團隊對系統(tǒng)運作的信息量。建立可觀測性的這項工作,雖然無法直接給系統(tǒng)帶來健壯性,但能夠使我們通過這些信息充分地了解到系統(tǒng)正在運作的情況,以至于最大程度地做出最合適的定位、判斷與決策。
在單體應用的場景下,我們也是需要可觀測性的,但是單體的架構(gòu)相對簡單,項目調(diào)試也更加便捷,無論是從復雜度和規(guī)模的角度來看,單體跟微服務相比都要低不少,也因此單體對可觀測性的需要,相比于微服務顯得沒那么重要。
而我們只要進行了微服務實施后,因為應用被拆分成了細粒度,從而導致了架構(gòu)從量變引起質(zhì)變,這個時候可觀測性的作用在微服務場景下被“無限放大”,也因此我們利用"可觀測性",給與我們提供應用與服務器的監(jiān)控、快速跟蹤與問題定位的功能。
可觀測性——可以由系統(tǒng)的外部輸出推斷其內(nèi)部狀態(tài)的程度,在軟件系統(tǒng)中,可觀察性是指能夠收集有關(guān)程序執(zhí)行、模塊內(nèi)部狀態(tài)以及組件之間通信的數(shù)據(jù)
而可觀測性三個維度組成:日志(logging)、跟蹤( tracing)、指標(Metrics)。
日志(logging)的定義特征是它記錄離散事件,目的是通過這些記錄后分析出程序的行為。
跟蹤( tracing)的定義特征是它處理請求范圍內(nèi)的信息,目的是排查故障。
指標(Metrics)的定義特征是它們是可聚合的,目的是監(jiān)控和預警。
|
可觀測性 |
類型 |
名稱 |
|
跟蹤( tracing) |
分布式鏈路跟蹤 |
SkyWalking |
|
日志(logging) |
日志系統(tǒng) |
ES+Filebeat+kibana |
|
指標(Metrics) |
系統(tǒng)監(jiān)控 |
Prometheus |
因此基于上述總結(jié),有日志記錄才能清楚知道當前系統(tǒng)的運行狀況和具體問題;指標是給與后續(xù)做優(yōu)化和定位偶發(fā)性問題的一些參考,沒指標參考就沒標準;我們平常做得多的調(diào)試、查看調(diào)用棧也是跟蹤的一種,但是在分布式時代,更多考量的是跨進程通信的調(diào)用鏈路。
日常有小伙伴曾問過我,如果出了那些很奇怪的問題,應該怎么定位、排查,本質(zhì)上其實還是得提高我們對這個問題或系統(tǒng)的信息量。
例如:是哪個模塊、接口出問題?具體服務器表現(xiàn)的情況是怎樣?CPU還是IOPS高?具體報錯是什么?
你看,說白了還是可觀測性的三個要素日志、跟蹤、指標。我們在工作中只有靈活結(jié)合這三者,才能提高我們對系統(tǒng)運行情況的信息量,信息量越高思考的越是更加全面,才能盡可能地減少“不知道問題出在哪”的狀況,所以當我們不清楚具體發(fā)生問題的原因時,建議你側(cè)重做一件事:就是盡可能想辦法,提高我們對問題與系統(tǒng)的信息量。
新思維:不可避免的分布式系統(tǒng)問題
上文的自動化和可觀測性,主要偏向于運維層面,而作為后端開發(fā)人員更加關(guān)注的是數(shù)據(jù)與應用服務的層面,特別是服務的拆分后,數(shù)據(jù)的一致性該如何處理。我相信這問題困擾著不少的后端開發(fā),接下來我將從冪等性、數(shù)據(jù)的一致性的讀與寫三個方向,跟大家分享一二。
冪等性
冪等性的定義——相同的參數(shù)在同一個方法里,無論執(zhí)行一次還是多次都會響應相同的結(jié)果
對于查詢和刪除的場景都有天然的冪等性,那么我們考慮冪等性的處理,更多是關(guān)注于新增數(shù)據(jù)與更新數(shù)據(jù)。
新增數(shù)據(jù)缺乏冪等性,則會因為網(wǎng)絡抖動導致請求重試或者是客戶端重復點擊,而引發(fā)的數(shù)據(jù)寫入重復,其解決方案也相對簡單,只要從客戶端生成主鍵傳給后端API 就可以解決,在這里得注意一點,只有請求成功或者主動刷新才會重新生成主鍵。
更新數(shù)據(jù)缺乏冪等性,主要會造成兩種情況,數(shù)值錯誤自增和ABA問題。首先,數(shù)值錯誤自增,可以結(jié)合事務憑據(jù)與新增冪等性的方式解決。

而ABA問題,解決方案相對簡單,可以在更新操作時帶上版本號判斷進行解決。
ABA問題對某條記錄先更新了A數(shù)據(jù),緊接著又更新了B數(shù)據(jù),理應是B是最新的,但是因為其他客觀原因使接口Retry或者別的問題,導致A數(shù)據(jù)再次請求覆蓋了B。
|
冪等性處理方案 |
||
|
場景 |
問題 |
方案 |
|
新建數(shù)據(jù) |
重復創(chuàng)建 |
由調(diào)用端預生成訂單號,唯一鍵約束 |
|
更新數(shù)據(jù) |
ABA覆蓋問題 |
添加版本號判斷 |
|
金額自增 |
使用流水憑據(jù) |
|
數(shù)據(jù)一致性(讀)
數(shù)據(jù)一致性讀,其實說白了就是做數(shù)據(jù)關(guān)聯(lián),從我過往用的解決方案來看共有三種,應用層的接口聚合數(shù)據(jù)、把更新頻率低的字段冗余存儲、把數(shù)據(jù)庫同步到一臺服務器進行SQL聯(lián)表處理,每種方式各有優(yōu)缺點,我結(jié)合切身體會和過往經(jīng)驗,以表格方式整理呈現(xiàn)出來,你可以根據(jù)業(yè)務場景自行選擇解決方案。
|
數(shù)據(jù)關(guān)聯(lián)方案 |
|||
|
方案名稱 |
方案描述 |
優(yōu)點 |
缺點 |
|
應用層數(shù)據(jù)聚合 |
分別調(diào)用查詢API,在業(yè)務邏輯層組裝,適用于簡單的關(guān)聯(lián)。 |
實現(xiàn)簡單 |
該方案只能適合簡單的查詢過濾,以主表為驅(qū)動的關(guān)聯(lián) |
|
冗余設計(反范式) |
在目標表添加冗余字段,適用于記錄遞增的,不適用于冗余字段更新頻繁,實現(xiàn)起來簡單,有擴展性問題 |
實現(xiàn)簡單,以應用層數(shù)據(jù)聚合方案有更多的過濾條件 |
冗余的字段如果更新存在同步問題,該方案適用于更新頻繁少的遞增日志類數(shù)據(jù) |
|
數(shù)據(jù)庫從庫集成 |
通過主從同步把相關(guān)表同步到一臺服務器做跨庫查詢,適用于復雜查詢、報表類的,有技術(shù)復雜度,從長遠收益來看能應對多種場景 |
通過強大的SQL解決復雜的報表類查詢 |
擁有技術(shù)復雜度,需要數(shù)據(jù)庫主從處理 |
數(shù)據(jù)一致性(寫)
寫的數(shù)據(jù)一致性,其實就是分布式事務,主流的方案有TCC、本地消息表(基于消息可靠的最終一致性)、異步請求/回調(diào)。其他的多數(shù)是基于以上幾種方法的變種,例如RocketMQ的消息事務,就是TCC+本地消息表的變種。篇幅有限,這里分享一篇我曾經(jīng)編寫的文章《.Net微服務實戰(zhàn)之必須得面對的分布式問題》。

分布式事務方案,用文字描述起來相對比較吃力,因此我通過流程圖代替文字描述展示給大家。下方表格是我對這三種方案的優(yōu)缺點與使用場景的總結(jié)。
|
分布式事務方案 |
|||
|
名稱 |
場景 |
優(yōu)點 |
缺點 |
|
異步請求/回調(diào) |
跨網(wǎng)絡環(huán)境、同網(wǎng)絡環(huán)境 |
實現(xiàn)簡單 |
強業(yè)務 |
|
TCC |
跨網(wǎng)絡環(huán)境、同網(wǎng)絡環(huán)境 |
有現(xiàn)成的框架、實現(xiàn)簡單 |
強業(yè)務 |
|
基于消息可靠的最終一致性 |
同網(wǎng)絡環(huán)境 |
有現(xiàn)成的框架、通用性強 |
中間件依賴 |
小結(jié)
從"拆"的層面來看,微服務的思想與優(yōu)勢給與開發(fā)人員帶來了更多的便捷性,如技術(shù)細節(jié)的隱藏與認知負擔的降低,使得開發(fā)人員更加關(guān)注自己負責業(yè)務代碼的迭代。
但是,拆了后還得重新整合,如果拆了無法整合,那么這樣的設計是沒有意義的。從"整合"的層面,微服務大大提高了對架構(gòu)師技能的要求,從通信交互到分布式問題,從自動化工程到可觀測性,每一項對于架構(gòu)師都是一種新的挑戰(zhàn)。
聊到微服務總繞不過SOA
無論是過去還是現(xiàn)在,只要聊到微服務總有個繞不過去的坎,那就是SOA。接下來,我會結(jié)合《Microservices》原文(https://martinfowler.com/articles/microservices.html#MicroservicesAndSoa)的[Smart endpoints and dumb pipes]模塊,簡單聊聊微服務與SOA的之間的關(guān)系,有助于大家更好地了解為何微服務比SOA更容易實施與盛行。
在《Microservices》原文里有一個模塊的標題是Smart endpoints and dumb pipes,如果用翻譯直譯成中文是[智能端點和啞管道],我結(jié)合了自己的經(jīng)驗并查閱了多種資料,最終認為[強服務和弱通信]作為它的翻譯才更加合適。

微服務的[強服務和弱通信],與SOA的[弱服務和強通信]是與之對應的,而SOA架構(gòu)的核心是ESB,ESB主要功能有消息路由、協(xié)議轉(zhuǎn)換、消息轉(zhuǎn)換和應用業(yè)務規(guī)則的復雜。仔細觀察下來,ESB基本上把微服務的基礎(chǔ)設施該做的都做了,如此高的技術(shù)復雜度,也是導致SOA在過去那些年無法普及跟實施的根本原因。
ESB的大而全的特點,在文中描述到SOA的通信是“聰明的”(smart pipes),而我也因為ESB的特點給SOA的翻譯是“強通信”。此外,我翻譯的微服務的“弱通信”,并不代表通信的功能有限,而真正的意義是弱化協(xié)議差異,使用統(tǒng)一、輕量級的通信協(xié)議,減少差異化、降低技術(shù)難度。

總地來說,基于兩者在通信層面的對比,我們因此能總結(jié)出它們本質(zhì)上的差異:SOA基于配置,微服務則基于約定。
關(guān)系的分類
既然上面已經(jīng)談到了微服務與SOA之間的對比,接下來,又不得不提SOA與微服務的關(guān)系了。我從多個方面的資料梳理后,總結(jié)出有這樣兩種看法:
- 微服務是SOA的最佳實踐(出自維基百科)—— 微服務是SOA的演進版,粒度更細,基礎(chǔ)設施去中心化。
- 微服務拒絕SOA的標簽(出自馬丁福勒的《Microservices》原文)——微服務與SOA,是兩個完全不同的架構(gòu)風格,只不過剛好長得像。

場景與目的
我相信,不少朋友看到SOA與微服務關(guān)系方面的話題時,肯定第一時間在想,無論是維基百科還是百度,都是寫著微服務是SOA的演化這還要說?是的,人云亦云的,大家聽多了看多了,不妨從新的觀點與角度看待一下問題,這樣或許會有新的碰撞與共鳴。
大家認為,微服務是SOA的演進版的理由也比較簡單,因為微服務基礎(chǔ)設施只不過是把SOA的ESB拆了,而微服務粒度更細,SOA更粗。從表面看起來的確是這么一回事,但是我認為,要看清楚它們關(guān)系的本質(zhì),就得從兩者各自的處理場景目的出發(fā)。
首先從微服務角度出發(fā),因為單體應用的大而全的高耦合與臃腫,隨著業(yè)務的發(fā)展迭代的時間越久,就會有各種各樣的問題,因此通過把應用拆成了多個"小"的服務,這里使用到了化繁為簡、分而治之的思想,解決原有單體的“痛點”和“難點”。

接著從SOA的角度出發(fā),在當時那個年代,希望把各種異構(gòu)的系統(tǒng)給整合起來,這些異構(gòu)的系統(tǒng),有可能是從其他地方買的,也有可能是研發(fā)的,也有可能是找外包做的,因緣由存在各種不確定性,所以希望通過一個"聰明的"ESB解決所有的"愚蠢的"問題,也是因此ESB的高復雜度,導致當年SOA那會只是炒得火熱,卻無法普遍落實。

總地來說,微服務以拆與約定作為出發(fā)點,而SOA是以整合與配置作為出發(fā)點,所以我個人認為從它們的出發(fā)點與目的的角度出發(fā),直接決定了它們在本質(zhì)上是完全不同的架構(gòu)風格。所以我更加傾向于《Microservices》原文提到的看法,微服務的倡導者拒絕SOA這個標簽的。
微服務與DDD的爭議
要是說SOA是微服務理不清的過去,那么DDD更是微服務的一塊攔路石。攔住的不是技術(shù)人員對它們的熱情,而是它們之間扯不清的“捆綁銷售”。
《Microservices》原文、《微服務設計》、《領(lǐng)域驅(qū)動設計精粹》,都有涉及到DDD對微服務劃分的參考。DDD戰(zhàn)略上的化繁為簡,與微服務的分而治之,這兩者的思想,可以說是不謀而合。成就了彼此,但是它們是否必須密不可分,又或者說無DDD就無微服務的說法呢?我是這么認為的。

DDD(領(lǐng)域驅(qū)動設計)的過去
2004年,埃里克?埃文斯(Eric Evans)發(fā)表了《領(lǐng)域驅(qū)動設計》一書簡稱DDD(domain-driven design ),自DDD提出后在軟件開發(fā)領(lǐng)域一直處于SOA相似的尷尬地位——宣傳得火熱,真正用的少。
隨著微服務架構(gòu)的興起,DDD才迎來了自己的時代。在上文提到三本書(《Microservices》原文、《微服務設計》、《領(lǐng)域驅(qū)動設計精粹》),都有涉及到使用DDD戰(zhàn)略來識別邊界上下文,從而劃分服務。總地來說,DDD并不是什么新穎的技術(shù),當年許多布道者也沒有把它帶火,如今卻靠著微服務流行起來而加速了DDD的盛行。

但是,DDD的盛行并非它所有的一切,我總結(jié)了DDD的一些核心概念,希望在我詳細敘述前,可以幫助到你快速了解DDD,以便于對后續(xù)內(nèi)容有個更好的理解:
領(lǐng)域驅(qū)動設計的本質(zhì)是,打破業(yè)務與開發(fā)之間溝通壁壘,建立通用語言;從而在戰(zhàn)略設計與戰(zhàn)術(shù)設計兩個維度上使用化繁為簡手段將通用語言逐步拆解成領(lǐng)域模型;從而確定業(yè)務與應用的邊界,保證業(yè)務模型與代碼模型的一致性。
戰(zhàn)略設計,從業(yè)務視角出發(fā),建立業(yè)務領(lǐng)域模型,劃分領(lǐng)域邊界,建立通用語言的界限上下文,界限上下文可以作為微服務設計的參考邊界。
戰(zhàn)術(shù)設計,從技術(shù)視角出發(fā),側(cè)重于領(lǐng)域模型的技術(shù)實現(xiàn),完成軟件開發(fā)和落地,例如我們常討論的聚合根、實體、值對象、領(lǐng)域服務等代碼邏輯的設計與實現(xiàn)。
結(jié)合上述的DDD概念知識與[業(yè)務與團隊]模塊所敘述,我們可以得到以下結(jié)論:業(yè)務需求是作為我們設計的核心輸入之一,要做好領(lǐng)域驅(qū)動設計,并非取決于對它本身的概念掌握程度如何,而在于如何使用這些方法論了解清楚業(yè)務需求后,進行正確的領(lǐng)域建模,就算對DDD的概念再熟悉不過,要是對領(lǐng)域業(yè)務缺乏了解,結(jié)果也是無法正確建模的,那跟用不用DDD其實已經(jīng)沒什么區(qū)別了,所以我認為這種做法與結(jié)果是本末倒置的。

PS:[業(yè)務與團隊]這個模塊是先前發(fā)表的文章《重新理解微服務之溫故》里的內(nèi)容,兩文之間沒有特別的前后關(guān)聯(lián)性,有興趣的朋友,可以閱讀完本文后可自行進行擴展閱讀。
【維基百科】領(lǐng)域驅(qū)動的局限性,為了幫助保證模型能作為一個單純并有用的語言結(jié)構(gòu),團隊通常必須在領(lǐng)域模型中實現(xiàn)大量的隔離和封裝。因此,基于領(lǐng)域驅(qū)動設計的系統(tǒng)可能會花費相對較高的成本。雖然域驅(qū)動設計提供了許多技術(shù)優(yōu)勢,如可維護性,但 Microsoft 建議僅將它應用于復雜領(lǐng)域中,在這些復雜領(lǐng)域中,通過模型和語言處理能夠在復雜信息中提供交流便利性的,并且能夠該領(lǐng)域達成共識。
文中我也多次聲明軟件工程是沒有“技術(shù)銀彈”的,結(jié)合上面領(lǐng)域驅(qū)動的局限性(維基百科)的敘述,DDD同樣也有它的適用場景與局限性,像軍工、金融等這些領(lǐng)域,就比較適合使用DDD,因為它們都具備了這兩個特征:
- 生命周期長(投入產(chǎn)出比)
- 邏輯足夠復雜(使用復雜對抗復雜)
而互聯(lián)網(wǎng)系統(tǒng)擁有需求高頻變動性、快速試錯和定制性,DDD是否需要引入,大家見仁見智。
DDD戰(zhàn)略的重要性
首先,DDD的戰(zhàn)略設計是可以使用指導劃分微服務,這點是毋庸置疑的,因為微服務的分而治之的思想,與DDD的化繁為簡,的確是不謀而合。

然而,我接觸過不少DDD的熱衷者,只要聊起DDD,全部都是DDD的概念與術(shù)語,同時把DDD戰(zhàn)術(shù)設計代入為微服務的全部,一開口的就是概念術(shù)語什么倉儲、什么領(lǐng)域服務、什么聚合根,Abp框架,盡扯跟微服務設計沒有半毛錢關(guān)系的東西,微服務的服務治理、分布式需要面對的數(shù)據(jù)一致性、冪等性和自動化部署卻閉口不談。
戰(zhàn)術(shù)設計其實就是為了落實面向?qū)ο笤O計與編程、從業(yè)務模型到代碼模型的翻譯,說通俗點就是針對單個服務與應用的設計,而由微服務架構(gòu)風格設計的系統(tǒng)是屬于分布式系統(tǒng),應更多關(guān)注跨進程的交互與服務的整合。
因此,DDD戰(zhàn)術(shù)設計是否引入,完全是看該服務對于系統(tǒng)的重要性。
在《微服務設計》一書提到過,微服務里的服務的復雜度能在兩個星期內(nèi)重構(gòu)完成的。如果遵從DDD戰(zhàn)術(shù)設計思想的應用,那么是使用復雜對抗復雜,因而會增加服務本身的復雜度。從個人的角度來看,DDD戰(zhàn)術(shù)與微服務拆分后降低復雜度的出發(fā)點,相違背。

因此我實施微服務的時候,最終還只是以戰(zhàn)略設計引入到微服務設計里,在期間我嘗試使用了事件風暴與其他同事合作,幫助識別我業(yè)務邊界從而確定界限上下文,而DDD戰(zhàn)術(shù)則根據(jù)日后業(yè)務穩(wěn)定,并且邊界清晰后,再考慮選擇性引入重構(gòu)。事件風暴是一個從拆解到整合的過程,過程中需要領(lǐng)域?qū)<遥ㄐ枨筇岢稣撸┖图夹g(shù)實踐者協(xié)作完成領(lǐng)域建模。
一般采用場景分析和用例分析盡可能分解出領(lǐng)域?qū)ο螅▽嶓w、命令、事件),可以從交流的過程中提取出領(lǐng)域?qū)<遥ㄐ枨筇岢稣撸┛谥械拿~、動作、觸發(fā)事件等,這是一個拆解的過程。
在軟件工程里沒有銀彈,微服務不是,DDD也不是,我們所做的永遠提供的是解決方案,同一個問題能有很多種解決手段,但是同一種解決手段并不能解決所有問題。
微服務需要引入聚合服務層嗎?
這是咱們這篇文章的最后一個話題了,也是我在微服務實踐時被同行問得最多的一個問題。
回顧我身邊,不同的時間,不同的人,實施同一種微服務架構(gòu)風格,都問過我同一個問題:他們網(wǎng)上找了很多資料,聚合服務層有的說引入,有的說不需要,那么,究竟微服務是否真的需要引入聚合服務層呢?
說句實話,這個問題也曾經(jīng)困擾過我。經(jīng)不斷的積累,我想我可以給這個問題一個明確的答案了:根據(jù)系統(tǒng)的復雜度與場景進行取舍,接下來,我將詳細敘述下我的思考結(jié)果。
API網(wǎng)關(guān)的類型
API網(wǎng)關(guān)可以作為多個微服務提供統(tǒng)一入口,它的思想類似面向?qū)ο笤O計的外觀模式,API 網(wǎng)關(guān)也稱為“面向前端的后端(BFF)”,因為它是為了滿足客戶端的接口整合需求而出現(xiàn)的。在《Microservices-Architecture-for-Containerized-NET-Applications》一書里有這樣個觀點,認為API網(wǎng)關(guān)主要分兩種類型:
- 基礎(chǔ)設施型API網(wǎng)關(guān)
- 自定義業(yè)務API網(wǎng)關(guān)
基礎(chǔ)設施型API網(wǎng)關(guān)比較容易理解,我舉個例子估計你就秒懂了,Kong 和 APISIX。這種類型的API網(wǎng)關(guān)主要把服務具有相同的功能抽象到上游服務,像鑒權(quán)、日志、限流、熔斷等通用功能,可以避免每個服務都需要去重新的實現(xiàn)這些相同的功能。

自定義業(yè)務API網(wǎng)關(guān),其實就是把多個微服務,適配成方便客戶端使用的API服務,避免客戶端組裝過多的API導致過于臃腫,也就是咱們上面說的聚合服務層,也有稱之為面向前端的后端(BFF)。
取舍與選擇
有些朋友一看,既然能減少客戶端的工作量和復雜度那這個不是好事么,還需要思考是否要引入?大家可別忘記了,在上文,我們多次提到了微服務的核心點——自治性。
如果在原有的基礎(chǔ)上加多了一層新的微服務,那么上游微服務就會受到下游微服務的更新而有所影響,如果下游服務接口有更新,上游服務也可能跟著一起更新,因此丟失了自治性。除此之外增加了調(diào)用鏈長度,也會降低系統(tǒng)整體的可用性。

無論用和不用好像都有問題,該怎么辦?取舍!
作為一個架構(gòu)師,大部分的工作就是根據(jù)問題場景選擇合適的處理方案,因為大部分的方案是無法做到“完美的”,因此我們很多時候還得做出一定程度的取舍。
從個人的角度認為,如果多個業(yè)務需要客戶端組合大于等于3個接口,我們可以舍棄部分自治性而選擇引入BFF,以此來降低客戶端對接的復雜度。如果客戶端的業(yè)務相對比較簡單,BFF則不需要引入,那可以最大程度的保證自治性。因此在開始設計微服務的時候,在不明確的情況可以暫時不需要考慮,隨著業(yè)務系統(tǒng)的迭代,系統(tǒng)復雜度越來越高,我們再考慮BFF的引入。

基礎(chǔ)設施型API網(wǎng)關(guān)與BFF兩者的存在不是非此即彼的,因為基礎(chǔ)設施型API網(wǎng)關(guān)不影響微服務的自治性,因此可以獨立于BFF的選擇,是否引入也取決于團隊的運維支撐程度如何,運維能力足夠則使用中間件支撐,運維能力有限,則在微服務的代碼里實現(xiàn)。
小結(jié)
總上文可見,方案是沒有“完美的”,設計只有"合適"與"不合適”,沒有“對"與"錯",架構(gòu)師永遠是在"取"與"舍"之間扎掙,而促使我們能做出那一次又一次的合適的選擇,只有積累與經(jīng)驗。
結(jié)語
該篇文章到這里就差不多結(jié)束了,我始終認為一圖勝千言,因此我在文中基于上述分享的知識點,給大家做了個腦圖,以便于幫助你回顧與總結(jié)。

微服務與DDD的見解,我也是再三思考了才打算寫出來,我清楚地知道有不少的DDD熱衷者認為這門技術(shù)是多么的“神圣”,當然曾經(jīng)我也是。
但是,隨著自己使用、接觸的技術(shù)越多,越是發(fā)現(xiàn)技術(shù)并不是那么的唯一、神圣,促使我們能在這條道路走得更高更遠的,是咱們的思維,是我們對這些技術(shù)做出適當的選擇與使用,而不是想著“一招鮮吃遍天”,我們是技術(shù)的創(chuàng)造者與使用者,而不是概念名詞的搬運工。
該類型的話題與見解,每個人接觸后的解讀可能都不一樣,我的不一定是標準,僅是我自己觀點上的分享,希望能與你產(chǎn)生見解上的碰撞與共鳴。
微服務是否需要引入聚合服務層這個例子,可以作為架構(gòu)師日常工作——取舍與選擇的縮影,通過這個例子我分享了API網(wǎng)關(guān)的類型,并且結(jié)合我的架構(gòu)設計方法論,從取舍與選擇回答了這個問題,咱們可以根據(jù)自己問題的場景選擇合適的方案進行應對。
好了,到這里我們就要結(jié)束了,非常感謝你耐心的閱讀,我們在后面的分享再見。同時期待后續(xù)的某幾個時段里,我與你能夠有更多思想上的交流、碰撞。如果愿意分享,這一講也歡迎轉(zhuǎn)發(fā)給你的朋友,和他一起討論。
還有,對這一講的內(nèi)容分享,有疑問或是不同的差異化、多元化想法,可以提出來,留言區(qū)里,我們多交流。
作 者:
陳珙
出 處:http://www.rzrgm.cn/skychen1218/
關(guān)于作者:專注于微軟平臺的項目開發(fā)。如有問題或建議,請多多賜教!
版權(quán)聲明:本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。
聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角推薦一下。您的鼓勵是作者堅持原創(chuàng)和持續(xù)寫作的最大動力!

浙公網(wǎng)安備 33010602011771號