?譯者 | 陳峻
審校 | 孫淑娟
目前,業(yè)界最常見的軟件范例有:單體(Monolith)和微服務架構兩種類型。兩者的邏輯結構如下圖所示。
通常:
- 微服務架構是將應用程序表示為微小的、松散耦合的服務集合。由于整體的復雜性被轉移到了服務的協調級別上,因此每個服務都代表了一種業(yè)務功能,可以更加容易地去定位相關代碼。
- 而單體架構是將幾個離散的功能組成一個單元,作為一個整體進行測試、部署和擴展。由于所有組件都是相互依賴的,因此通常不能夠單獨運行。這就意味著某個模塊中的錯誤,可能會減慢、甚至破壞整個應用程序。
1.微服務架構的優(yōu)點
一直以來,我們都沿用且諳熟單體架構,下面,我們先主要來討論微服務架構的各項優(yōu)點:
- 易于擴展
- 應用組件相互獨立
- 有清晰的邊界,并能通過HTTP實現通信
- 可以使用不同的編程語言和數據存儲
- 開發(fā)過程可被分到多個團隊
- 可被獨立部署
- 易于更新和維護
- 使用較小的代碼庫
2.微服務架構的缺點
- 難以監(jiān)控
- 具有更為復雜的服務部署
- 服務之間的通信需要額外安全加固
- 性能會有所降低
- 鑒于分布式系統的遠程調用較慢,因此經常存在著編程難度大和失敗的風險
- 增加了運營的復雜性
3.何時選擇微服務
?2001年,面對各種應用請求的增加,編碼問題突顯、開發(fā)的延遲、以及服務間的相互依賴性等問題,Amazon逐漸意識到需要從頭開始重構其系統,因此它將其單一的應用程序分解成小型的、獨立的特定于服務(service-specific)的應用程序,開創(chuàng)了微服務的架構。該架構實現了由一種服務接受訂單,另一種服務生成待購買的推薦商品列表,而第三種服務負責提供簡單的身份驗證服務等模式。正如Martin Fowler早在2015年,針對如何構建實用的軟件,所給出的建議那樣:“幾乎所有成功的微服務案例都是從拆分一個巨型的單體架構開始的。”當然,僅僅根據現代化趨勢來選擇微服務,不一定是正確的。通常,我們認為如下的應用和代碼設計需求,更適合企業(yè)選擇轉向微服務:
- 繁重的系統負載,需要與不同的支付系統進行交互。
- 用戶需求不斷增長和規(guī)模持續(xù)擴大,現有應用系統常出現中斷。
- 單體應用變得不夠靈活且無法升級。
- 為了在競爭激烈的業(yè)務環(huán)境中取得成功,需要加快應用的開發(fā)和發(fā)布時間,并可在后續(xù)著手進行功能的更新與升級。
- 需要實施人工智能之類高級的商業(yè)智能方案,以獲得更深入、更具競爭力的業(yè)務數據、報告和分析。
- 目前的基礎設施無法提供所需的橫向可擴展性,無法處理大數據的處理負載。
上圖是Amazon在2008年完成的被稱為“死亡之星”的微服務基礎設施
4.遷移至微服務所面臨的挑戰(zhàn)
企業(yè)在從單體架構向微服務架構的遷移過程中,往往會遇到各種技術和組織方面的挑戰(zhàn),因此我們有必要了解與之相伴的各類風險:
- 麻煩且耗時。由于從單體應用整體遷移到微服務是非常耗費時間和精力的,因此企業(yè)往往選擇以“小步快跑”的方式進行分步遷移。如果需要在遷移的過程中引入新的服務特性,那么開發(fā)團隊還要投入更多的精力。
- 成本較高。無論是從開發(fā)與編寫代碼的角度,還是從支持、運維、以及更改的角度,遷移到微服務的成本都比較高。企業(yè)需要在構建基礎設施、開發(fā)文檔、以及重構應用等方面進行大量的投資。
- 由于微服務是一個分布式系統,因此開發(fā)團隊需要選擇,并實現基于消息傳遞或RPC的進程間通信機制。
- 移動代碼庫。為了順利地將數據從現有的單體架構提取至配合微服務的數據庫和代碼庫,我們有可能需要重構其實現的過程,并通過完備的測試覆蓋率,以避免引入新的bug。
- 組織的轉變。為了實現遷移,企業(yè)需要將現有的大型項目團隊,拆分成能夠自主開展工作的小型團隊。同時,企業(yè)仍需要保持組織架構的一致型。
- 團隊應對其服務負責。在完成遷移后,各個團隊將擁有自己的代碼庫,一旦出現服務交付的失敗,他們將不再可以歸咎他人,而需要從自身找原因,動手解決,負責到底。
- 此外,在系統不宕機的情況下進行遷移,并保證用戶持續(xù)有權訪問應用程序。這本身就有一定的風險。
可見,由于需要一定的資源投入,微服務架構可能并不總是對初創(chuàng)型或中型企業(yè)有利。
5.從審查和分析開始遷移
?正如前文所提到的,從一個單體架構遷移到微服務架構不但繁瑣耗時,而且存在著風險。那么,我們怎么能夠在遷移之前就認定微服務一定適合本企業(yè)呢?《微服務遷移模式》一書的作者--Sam Newman,建議開發(fā)人員在動手之前考慮如下三個方面的問題:
- 您希望達到什么目的?
- 您考慮過使用微服務的折中方案嗎?
- 您怎么判斷遷移的有效性?
下面,我們根據Sam Newman的建議,提出一套分析方法:
6.設定目標
- 定義遷移對于業(yè)務和最終用戶的好處,明確企業(yè)想通過微服務獲得什么。例如:是為了快速開發(fā)的整體進程,還是需要減少服務的相互依賴、亦或增加正常運行時間、以及增強可擴展性。
- 同時,我們需要事先預測系統在完成遷移后的負載和用戶數。
7.盤點業(yè)務與功能現狀
企業(yè)的應用架構師需要能夠找到關聯的代碼對象,并將它們與系統中的業(yè)務功能相匹配。
- 在現有的單體架構中,可能許多函數由于在其使用域中尚未被明確地定義,或者是業(yè)務流程的邏輯較為混亂,因此往往無法被直接遷移或替換。例如:某個組件持續(xù)與其他多個組件相關聯,那么就很難被拆分為多個普通的微服務。
- 分析當前的功能,并考慮對其進行優(yōu)化。例如,通過剔除大量不必要的信息,來優(yōu)化數據庫的查詢,或者可以直接更換新的硬件,以及通過開發(fā)新的功能,來引入微服務。
8.團隊的能力和折中方案
- 評估團隊的DevOps成熟度水平,包括:是否了解DevOps的核心實踐,是否具備基本的自動化文化?運營團隊是否支持腳本式部署?是否擁有代碼即基礎設施?是否已有代碼評審的標準?團隊只有具備了這些成熟的開發(fā)和運維實踐能力,才能發(fā)揮微服務架構的優(yōu)勢。
- 由于依賴性在服務之間創(chuàng)建了連接,模糊了組件的邊界,并導致它們必須組合成單個的模塊功能,因此團隊只能嘗試著從應用的垂直或水平方向進行擴展。
- 根據項目的特點,僅分離并遷移諸如:電子郵件的發(fā)送、通知的推送或電話的呼叫等部分受限的功能。當然,如果您只想從儀表盤系統內剝離出來,從已連接的數據庫中收集與分析數據,進而單獨形成微服務的話,那么應全面考慮相互之間的關聯性。
9.選擇可擴展平臺
?為了保證在構建和遷移至微服務時,用戶的體驗不會受到影響,開發(fā)團隊應邀請用戶一起進行業(yè)務需求分析,構建詳細的業(yè)務邏輯和數據流。有時,您可能需要一個專有的平臺來擴展微服務的資源,并能夠支持自動化的調整。在此方面,您可以使用由云服務提供商托管的無服務器類型的基礎設施,例如:Google Cloud、Microsoft Azure和Amazon Web Services等。
10.考慮創(chuàng)建跨職能團隊
?在遷移的過程中,企業(yè)需要團結包括開發(fā)人員、質量保證(QA)人員、操作運維人員、以及企業(yè)所有者等角色,以微服務為驅動,來創(chuàng)建可以從事設計、構建、部署和維護的服務型團隊,并盡量簡化不必要的審批流程。杰夫·貝索斯曾說:“我們試圖創(chuàng)建一支規(guī)模不超過兩個比薩餅的隊伍。”他稱之為“雙披薩團隊規(guī)則”。
?下面,我將向您介紹從單體架構遷移到微服務架構的一些值得注意的參考經驗。
11.定義邊界
?正確的邊界往往是有效的微服務架構的基礎。相反,如果邊界定義錯誤,則可能導致在新的微服務中,各項功能被頻繁更改,特別是那些提供調用的微服務接口,很可能會在隨后的集成測試中持續(xù)“浮動”。而且,由于不同微服務出自不同的團隊,因此它們會牽扯到團隊之間的各種反復協商與較量。
一個典型的域分離的例子源于軟件公司Istio。由于前期定義不足,在遷移到微服務后不久,Istio團隊便從用戶處得到了各種反饋。他們很快地意識到,微服務并非像他們最初想象的那么實用。其主要原因是:所有控制面的服務都是被一股腦部署和使用的,并且共享著相同的管理和安全域。因此,為了大幅降低Istio的操作復雜性,以更少的精力滿足業(yè)務需求,并能夠更容易地開發(fā)出服務產品,他們決定從微服務架構回歸至單體架構,并按照相關的技術標準來構建單體架構,識別架構中的業(yè)務域邊界,并使用公共的API作為接口,來予以實施。
12.選擇單體架構中可以被遷移的功能
?在遷移之前,一個由工程師和作用域專家組成的團隊,可以通過了解現有的實現方式、依賴關系、以及內部事件等途徑,來確定哪些功能組可以作為微服務,提供最大的產品價值;而哪些剩下的功能,則可以酌情保留在單體架構中。
13.微服務的獨立數據存儲
每個微服務都需要有一個數據存儲庫,這在某種程度上給分離數據的管理增加了難度。由于單個存儲系統很容易因為失去同步,而出現不一致性,因此您需要使用能夠執(zhí)行主數據管理(master data management,MDM)的工具。例如,它可以通過檢查每個訂閱者ID的數據庫,及時發(fā)現其中是否存在相同的ID。據此,就算某個服務停止了工作,它也能夠確保用戶數據的安全性。當然,最理想的狀況是將數據同時存儲在微服務和單體表中。
14.保留微服務的代碼
?通常,我們與其在性能良好的微服務中添加、重寫一段代碼,不如為新的或更改后的代碼創(chuàng)建或部署一個新的微服務。據此,我們不但可以簡化新代碼的測試,而且能夠減少現有服務在微服務中出錯的可能性。
15.微服務的單獨構建
?通過對每個微服務采取單獨的構建,我們可以在存儲庫中,以適當的修訂級別獲取組件文件。
16.在容器中部署微服務
?為了盡量簡化,我們最好使用同一種工具,在容器中部署微服務。例如,Docker便是被廣為推薦的一種容器標準。
17.典型的成功遷移案例
?Netflix(奈飛)?
為了能夠全天候地運營,Netflix需要一種架構來優(yōu)化交付速度,并擴展到下一個數據量級。因此,Netflix決定擺脫數據中心里由關系型數據庫所帶來的,在垂直向擴展時的單點故障,使用NoSQL數據庫對數據模型進行非規(guī)范化處理。同時,該公司采用了由云服務提供的高度可靠的、可橫向擴展的分布式系統,并通過選擇AWS作為云服務提供商,獲得了大規(guī)模且廣泛的服務和功能。此外,微服務架構也方便Netflix將系統分成獨立的服務,其中包括:存儲所有觀看節(jié)目的服務,負責每月信用卡支付的服務,以及分析觀看歷史以提供類似電影節(jié)目的服務。該公司的全部遷移過程耗時整整七年。
?Netflix微服務基礎設施的邏輯圖
Wix.com?
由于Wix.com的應用程序是彼此連接的,因此系統一旦在某個部分出現問題,都會導致整個系統的崩潰。對此,Wix.com開創(chuàng)了新的集成和端到端測試模式,運用JSON/RPC協議,在SpringMVC的基礎上,構建了一套微服務框架。通過遷移,它們解決了處理微服務之間的通信、故障與調試等的技術債。
Cloud Elements
?Cloud Elements使用諸如Minikube和Docker之類的工具,管理本地和遠程運行的服務。由于所有的微服務都在Node.js中,因此他們使用諸如Ava等基于npm的單元測試包,實現了代碼測試的全覆蓋,以應對業(yè)務的指數增長,并根據新增的需求不斷迭代其微服務。
Best Buy(百思買)
?過去,相互依賴的架構造成了Best Buy在業(yè)務部署上的難題。長時間的宕機給其在線業(yè)務的維持帶來了不小的挑戰(zhàn)。開發(fā)團隊往往需要把新的功能逐個打包,再累計發(fā)布。如今,他們通過諸如:Chef和Jenkins等工具,實現了持續(xù)集成與部署,并且將數據庫遷移到了Riak(一個分布式NoSQL鍵值數據存儲)上。
18.小結
?綜上所述,我們是否應該跟上軟件架構的趨勢,放棄單體架構,投入微服務的懷抱,目前尚無絕對的定論。我的觀點是:如果目標項目既沒有高負載,又無頻繁地與外部服務交互的需求,那么我們便可以選擇或維持單體架構;而如果系統必須在大量的負載和服務請求下工作,那么微服務架構會是更好的選擇。
我們再來看企業(yè)的組織結構層面。如果貴公司只有一個開發(fā)團隊,那么建議您集中精力構建和維護單體架構;但是如果您有幾個IT團隊,可以同時開發(fā)同一個產品的話,微服務會比較合適一些。
客觀而言,微服務架構有利有弊,它只是構建軟件的另一種方式。是否應該選擇完全取決于應用程序的業(yè)務需求。當然,您也可以從一個簡單的單體架構開始,隨著服務需求的增長,慢慢將應用組件獨立出來,并遷移到微服務中。這可能是更為穩(wěn)妥的應用實踐。
原文鏈接:https://dzone.com/articles/Monolith-vs-microservices-architecture-split-or-no
譯者介紹
陳峻 (Julian Chen),51CTO社區(qū)編輯,具有十多年的IT項目實施經驗,善于對內外部資源與風險實施管控,專注傳播網絡與信息安全知識與經驗;持續(xù)以博文、專題和譯文等形式,分享前沿技術與新知;經常以線上、線下等方式,開展信息安全類培訓與授課。?