1. 程式人生 > >微服務架構適用場景分析

微服務架構適用場景分析

核心要點

  • 微服務並不是什麼靈丹妙言,在現代架構中,它有自己的位置,但並不適用於任何的地方;
  • 在判斷基於微服務的方案是否適合時,理解業務域是至關重要的;
  • 單職責原則是劃分微服務邊界的關鍵;
  • 與其他架構風格類似,微服務是由一系列的原則來監管的;
  • 微服務必須在更廣闊的分散式架構和分散式計算上下文中進行考量。

在本文中,我們將會深入研究主資料管理(Master Data Management,MDM)場景中微服務架構的適用情況,並且會分析在問題域中,如果需要計算密集型的任務,基於微服務的架構所面臨的挑戰,比如在計算無擔保消費信貸組合的預期損失的時候。

我們首先會介紹業務架構的元模型,並使用模型的元素及其關聯關係定義業務域和問題域。然後我們採用領域驅動設計的方式去理解複雜的業務域,並幫助我們建立技術解決方案。

隨後,我們將會引入微服務這種新的架構正規化,對其進行剖析並簡單闡述其優勢和不足。我們還會分析使用微服務來實現MDM Data Hub的適用情況。

最後,我們會討論針對大容量資料的計算密集型任務時,基於微服務的架構所面臨的侷限性,探討這種架構風格是否適用於這種型別的應用。

業務架構元模型

圖1引入了一個簡化的業務架構元模型,在本文中,我們都會使用這些元素來定義業務域。元模型包含了五個元素,我們對這些構建塊提供了簡潔的定義。

(點選放大影象)

圖1:簡化的業務架構元模型

業務服務(Business Service)會暴露滿足客戶業務需求的一些功能,不管這些客戶是組織內部的還是外部的。業務能力(Business Capabilities)表明組織要做些什麼事情來達成其業務目標,它並不反映該如何做。它們是業務架構的頂層元素,屬於戰略業務域,並且由組織的業務原則來監管。通常來講,會使用一個或多個業務能力來實現一個或一組業務服務。業務能力要通過多個業務功能(Business Function)來具體化實現,業務功能又通過多個業務活動(Business Activities)來實現。業務活動會被組織成業務過程(Business Processes)。業務功能定義為一個業務行為元素,該元素會基於給定的標準(一般是所需的業務資源和/或許可權)對行為進行分組。業務能力包含一個或多個業務功能。簡化起見,業務過程定義為一個行為元素,它會基於排序的活動對行為進行分組。這樣的話,就能生成一組定義好的產品或業務服務。最後,業務活動代表了在業務過程中要完成的工作。(業務活動可能是原子的,也可能是複合的,但是它們之間的差異並不會影響我們目前討論的話題。)

業務能力、功能、過程和活動是由組織中的一個或多個角色(也就是某個人或團隊)來執行的。

與建築行業不同,軟體開發的方法論依然還處於非常模糊的狀態。在過去的20年間,湧現出很多的方法論,首先是瀑布式的方法,然後敏捷方法,比如SCRUM,還有敏捷相關的方法,比如極限程式設計(Extreme Programming,XP)以及統一軟體開發過程(Rational Unified Process,RUP)。

領域驅動設計(Domain-Driven Design,DDD)是軟體行業最新的方法論,它所設計的軟體與問題域的概念模型是匹配的。換句話說,領域驅動設計倡導基於實際業務的具體用例進行建模。按照最簡單的形式,DDD會將業務域解耦為更小的功能塊,要麼在業務功能級別,要麼在業務過程級別,這樣的話,複雜的業務或問題域就能更容易地理解並通過技術手段來解決。為了展現其效果,我們使用圖2闡述之前提到的業務架構元模型中的各個元素是如何進行協作並組成兩個業務域的。

因為面向服務架構(Service Oriented architecture,SOA)的很多文件化實現遭到了失敗,或者只是這種架構的自然演化,在最近的幾年間出現了一種新的架構風格。儘管植根於SOA,但是它集成了一項很重要的面向物件設計原則。這種新的架構風格以單職責原則(Single Responsibility Principle,SRP)為核心,倡導將多個獨立的服務應用組合起來,並且藉助限界上下文(bounded context)使這些服務應用從一開始就能獨立進行開發。DDD構件代表了一個或多個業務能力的邏輯子集,能夠從給定角色的角度提供業務價值。邏輯子集的邊界進而會定義業務上下文,角色會被限制在這個上下文中進行操作,如圖2所示。這種架構風格的名稱就是微服務。

圖2:領域驅動設計與微服務的概念檢視

來自ThoughtWorks的James Lewis和Martin Fowler是這樣來定義微服務的:“簡而言之,微服務架構風格會將一個應用開發為一系列小的服務,每個服務執行在自己的程序中,彼此之間通過輕量級的機制實現通訊,通常會是HTTP資源API。這些服務是圍繞業務能力構建的,並且能夠通過自動化的部署機制獨立部署。其中,會有一個最小化的中心管理機制,管理這些服務,這些服務可能會使用不同的程式語言編寫並使用不同的儲存技術”。微服務的這個定義非常重要,因為它識別出了一些重要的原則(tenets),本文稍後會用到這些原則進行判斷。圖3剖析了微服務,並在此基礎上試圖視覺化這些基礎原則。

(點選放大影象)

圖3:微服務剖析

為了闡述領域驅動設計和基於微服務的架構,我們以交易成本分析(Transaction Cost Analysis,TCA)的場景作為樣例。圖4描述了一個典型的交易時間線,展現了這種分析通常會在何處進行。

資產管理公司可能會有最佳的投資模型,但如果金融工具不採取實際交易的話,那它們就毫無價值。任何資產組合的總業績都會受到標的資產類別的選擇和分配、實施質量以及其他關鍵維度的影響。實際上,通過購買和銷售金融工具來實現投資組合時,它的成本通常會降低投資組合的回報。

(點選放大影象)

圖4:交易的時間線

投資組合的實施成本能夠將高質量的投資變成中等收益的投資,或者將低質量的投資變得無利可圖。因此,投資經理必須要主動地管理交易成本,因為更低的交易成本就意味著更高的投資回報。通過為投資策略和交易業績提供更高的透明度,TCA能夠幫助投資經理降低交易成本並確定其投資組合交易的有效性。

因此,使用我們前面提到的業務架構元模型,按照最簡單形式,TCA可以建模為一個業務能力,它由三個業務功能具體實現,如圖5所示。

圖5:交易成本分析——簡化的業務模型

交易成本度量(Transaction Cost Measurement)業務功能通常會受到顯式和隱式成本的影響,如下表所示。

表1

關於顯式成本和隱式成本的介紹表明交易成本度量這個業務功能至少可以進一步分解為兩個子域:顯式交易成本度量(Explicit Transaction Cost Measurement)和隱式交易成本度量(Implicit Transaction Cost Measurement)。為了簡單起見,我們省略了其他業務功能的DDD分解。

圖6為顯式交易成本度量和隱式成本度量這兩個業務功能建立了基本的context map。Eric Evans在其關於DDD的重要著作中指出,Context Map是明確上下文邊界的主要工具,它在限界上下文和業務領域的角度展現了微服務。在TCA樣例中,針對每個子業務領域,識別出了五個可能的微服務。

(點選放大影象)

圖6:針對交易成本分析的簡化Context Map

基於微服務的架構提供了很多的優勢。這種正規化所引入的模組化能夠提升開發的便利性和開發速度,從而匹配業務的節奏。更新某個子集的功能也會非常容易,因為它只位於一個或幾個軟體之中。微服務的模組化特性還會增強安全性並隔離故障。如果給定的一組程式碼被損壞或出現問題,它能夠與其他的服務完全隔離,從而避免整個應用出現不可用的狀況。

但是,微服務也有不少的缺點,編排(orchestration)就是其中很主要的一個樣例。大量微服務的協作可能是很有挑戰性的,如果每個微服務只對自己的互動負責的話,那麼更會如此。資料儲存是可能面臨困難的另外一個方面。因為每個微服務負責自己的持久化,所以在由多個微服務組成的應用中,非常有可能出現數據冗餘的情況,這會影響到主資料管理(Master Data Management)傳統的操作方式。微服務會影響到的另外一個領域就是報告。除此之外,微服務的劃分還會讓整合測試變成一個很困難的問題。這些收益和缺點並非詳盡無遺的,我只是使用它們來完成關於微服務的概要介紹。

本文剩餘的部分將會引入兩個特定的主題域,探討這種新的正規化是否適用。這也是微服務架構第一次在主資料管理的場景下進行充分性檢驗。它的適用性在計算密集型的任務中會面臨一些挑戰,比如總損失的分佈計算。

主資料管理是一個很寬泛的領域,有個簡短的定義能夠讓我們快速對其達成共識。主資料管理是一個程序和技術的框架,致力於建立和維護權威的、可靠的、可持續的、準確的和安全的資料環境,這個環境代表了現實情況的一個單一、全面的版本,用於主資料及其關聯關係。主資料指的是對企業、關鍵業務過程以及應用系統至關重要的實體、關聯關係以及屬性。客戶資訊、州、郵政編碼、貨幣符號(Currency Symbol)或安全收報機(Security Ticker)都是這樣的實體。

在功能上來講,MDM需要通過清理、充實和丟棄冗餘資料來對主實體進行主動管理,如下面的用例圖所示。

(點選放大影象)

圖7:MDM用例圖——簡化的檢視

多年以來,MDM的技術實現在持續進步,以便於更好地解決該領域的企業級需求。這種演進以引入新的架構正規化為特點,其目的是滿足MDM技術解決方案在演進性、可維護性、可擴充套件性以及效能方面的要求。

圖8以視覺化的方式追溯了MDM Data Hubs的架構演化過程,從客戶端-伺服器應用開始,直到可能基於微服務的架構實現。在接下來的幾個章節中,我們將會回顧一下如何藉助單體架構以及傳統的SOA架構實現Master Data Hub的方案。隨後,我們會將基於微服務的架構作為一個可能的架構替代方案。

(點選放大影象)

圖8:MDM Data Hub——架構演化

在分散式架構尤其是面向服務的架構出現之前,主資料管理通常會作為單體應用的一部分來實現。MDM的功能以及關聯的邏輯會與應用本身所解決的特定業務域或問題域的功能關聯到一起。同樣,MDM資料的持久化也會與系統的事務化域(transactional domain)關聯在一起,如圖9所示。例如,在客戶端-伺服器交易應用中,不管是用PowerBuilder 6還是Visual Basic 6編寫的,通常都會將主資料關聯的實體比如Customer、State Code或Security放到用於儲存單個事務的底層資料庫中。

圖9:單體/客戶端-伺服器MDM Data Hub架構

在這種方式下,MDM和事務性資料在物理上非常接近,所以幾乎沒有延遲,但是從架構的角度來看,MDM和業務特定功能的耦合將會引入架構的剛性,阻礙每個功能區域的獨立演化。另外,在企業級來說,這種架構正規化通常會造成功能和資料的重複,如圖10所示。

圖10

採用分散式架構,尤其是SOA,能夠將MDM相關的功能和持久化與領域相關的實現解耦(關注點分離的原則,Separation of Concern),如圖11所示。不管MDM的架構風格是什麼(Repository、Registry或其他),這種分離都會增加架構的靈活性,允許每個域解決方案進行獨立地演化以滿足各自的功能需求。但是,直到NoSQL資料庫出現之前,MDM資料的持久化依然是使用關係型資料庫,因為當時並沒有合適的替代方案。

(點選放大影象)

圖11:傳統的SOA MDM Data Hub架構——Registry風格

從資料架構的角度來看,很多的MDM Data Hub實現使用了Master-Slave構造或它的變種,比如sharding。在Master-Slave方式中,會有很多的伺服器處理讀取請求,但是隻有一個(在sharding場景下會有幾個)伺服器實際執行寫入操作,這樣的話,就能維護主資料的一致性狀態,如圖12所示。

圖12:Master-Slave架構

這種架構通常會引入單點故障,可能會限制高可用性以及無縫水平擴充套件的能力。因此,在實現MDM Data Hub解決方案時,資料架構是需要考慮的一個重要方面。隨著NoSQL資料庫的出現,這一點變得尤為重要,因為這些資料庫提供了儲存主資料的可靠替代方案,在與微服務結合時,它們的重要性更加明顯。

傳統的SOA已經在MDM和以業務為中心的OLTP應用間實現了功能與持久化的分離,因此主資料能夠實現企業內更高的複用。微服務構建在這些收益之上,為分散式架構提供了更好的支援,如果涉及到多個zone的話,其收益會更明顯(會在單獨的文章中進行討論)。它們關注功能邊界和部署模型,能夠讓微服務更靠近消費者進行部署,可能會增強可用性、可擴充套件性和吞吐量,如圖13所示。同時,每個微服務只會對自己的資料負責,這意味著主資料的結構和儲存可以進行定製,以便於更好地適應使用它們的服務或系統。例如,State Code的微服務可以通過key-value倉庫來實現,而不一定採用RDBMS中的表。這種微服務的多個例項可以部署到不同的物理區域上,從而滿足東海岸執行的客戶端應用以及西海岸執行的賬單服務的需求。

(點選放大影象)

圖13:基於微服務的MDM Data Hub架構

但是,對這種架構正規化可能會出現缺點進行評估是非常重要的。例如,在每個主資料相關的微服務中,可能會重複出現數據的合理化或實體解析(rationalization or entity resolution)、資料清洗和強化(enrichment)功能。同時,在組織內,主實體的唯一性恐怕會難以保證,因為MDM的本質傾向於從企業轉移至更靠近限界上下文。因此,在維度設計中,我們甚至需要重新考慮使用一致的維度。

在接下來的內容中,我們將會探討微服務架構是否能夠用於需要密集計算的業務領域。為此,我們將會以5000萬份記錄作為樣例,計算零售信用卡投資組合的總損失分佈。圖14在一個較高的層級,以視覺化的方式展現瞭如何基於單個損失事件生成總損失分佈的步驟。

(點選放大影象)

圖14:總損失分佈的概要

從年度總虧損的角度來看,零售信貸市場有其獨特之處,與大宗的貸款不同,我們無法通過簡單地縮減模型就能進行分析。按照一位分析師的說法,“零售信貸市場會向那些沒有進行評級的借款人提供資金。每筆貸款的規模相對較小,這就意味著每筆貸款的絕對信貸風險也比較小。任何一筆零售貸款的風險都不會導致銀行的破產。因此,確定每筆零售貸款信用風險的成本往往會高於規避風險所帶來收益,查清每筆零售貸款的信用風險可能並不是一件值得去做的事情。”

因此,開發一種技術方案來確定幾個賬戶的信用風險可能並沒有太大的經濟意義,如果要解決不安全貸款相關的信用風險問題,所給出的技術解決方案必須要基於大量的賬號來操作,只有這樣在經濟上才是划算的。同時,該業務領域相關的資料量是造成基於微服務的架構不適合解決計算密集型任務的關鍵因素之一。在計算不安全的信用卡投資組合所帶來的總損失分佈時,本文從三個方面介紹了基於微服務的架構所面臨的挑戰。具體來講,包括:

  • 資料的多樣性(Heterogeneity)與資料儲存
  • 計算能力/強度
  • HTTP語義的不適用性

資料的多樣性與資料儲存

在概念上,微服務鼓勵基於限界上下文擁有自己的資料和儲存。每個微服務相關的資料格式、內容以及儲存形式都可以採用最適合業務功能的方式,如下圖所示。因此,在基於微服務的架構中,我們通常會看到各種資料倉庫(RDBM與NoSQL)和模式。

圖15:微服務架構——概念檢視

但是,預期損失(Expected Loss)和風險值(Value-at-Risk)的計算都依賴於時序資料。這表明源資料不僅需要是完整的,還要非常一致和標準,這樣在資料模式多樣性方面所能留下的空間就很小了。因此,為了適應時序資料的需求,圖15所闡述的概念架構就會演進成圖16的樣子。這樣的話,微服務會共享相同的資料儲存,兩個repository例項就顯得冗餘了,這違反了微服務的一個核心原則。

(點選放大影象)

圖16

結合圖16,從功能的角度來看,下圖描述了生成總損失分佈(年度總虧損)時,可能採用的context map。從概念上來看,將這些步驟拆分為微服務似乎是可行的。

圖17:計算總損失分佈時,可能採用的Context Map

但是,在這裡資料阻抗(data impedance)可能會再次違反微服務的一個核心原則。總損失分佈的計算要從單個損失事件的計算開始。按照前文所述,所有的損失事件記錄必須要符合相同的模式。

第一步需要為所有的損失事件建立風險矩陣(risk matrix)。第一步計算得到的儘管是中間結果,但也可能需要進行儲存。為了本文的簡潔性,這裡不再討論ACID的需求。為了遵循微服務的原則,每個微服務要負責管理自己的資料和底層儲存,如圖18所示。

圖18

第二步涉及到生成損失分佈。這個限界上下文的微服務需要第一個微服務的結果來完成它的功能,但是Loss Distribution微服務不應該直接訪問Risk Matrix Loss Data上下文中的資料,否則的話,就會引入緊密耦合了,這樣會違反微服務架構的另一個原則,如圖19所示。

圖19

Loss Distribution微服務有兩種方式來獲取來自Risk Matrix Loss Data上下文中的資料。第一種方式就是對Risk Matrix Loss Data微服務進行READ呼叫,如圖20所示。但是,這種方式並不理想,因為這涉及到轉移上百萬條的記錄。

圖20

第二種方式就是將來自Risk Matrix Loss Data上下文的資料複製到Loss Distribution上下文中。比起前面的方案,這種方式在技術上更加易於接受,但是,這裡所需的資料轉移會影響整個程序的效能,當需要轉移上百萬行的記錄時,這種影響會更加明顯。

VaR Calculation和Total Loss Distribution微服務會遇到和上面描述完全類似的問題,所以簡潔起見,這裡我就將其省略了。

通過引入資料快取,上面所討論的資料轉移的問題可以得到解決,如圖21所示。這種設計在本質上是讓微服務共享相同的資料儲存,儘管是虛擬的,但是它再次規避了微服務架構的一個主要原則。另外,值得一提的是,在每個限界上下文中,為了持久化中間結果,它們的資料儲存都有可能會增加,在以上的三個步驟中,都允許重新執行計算。

圖21

圖21中的架構會引出微服務架構不適合計算密集型任務的第二個原因,那就是依賴於所選擇的基礎設施架構。

計算能力/強度

圖22闡述了託管微服務的典型基礎設施配置。第一個方案展現的微服務#1部署到了3個節點的叢集中,其中每個節點包含兩個CPU(這裡負載均衡器被省略掉了)。第二個配置所展現的微服務# 2部署到了一個虛擬叢集中,它有兩個虛擬伺服器組成,每臺機器同樣有兩個CPU。

圖22:微服務的典型部署架構

通常來講,這些基礎設施配置對於處理OLTP的系統來講是非常合適的(容錯、負載均衡、可擴充套件性),但是對於計算密集型的任務,它的處理能力可能就不夠了,當與任務群(task farm)和網格計算(grid computing)對比時,它的不足就會更加明顯了,如圖23所示。

(點選放大影象)

圖23:網格架構與任務群並行

HTTP語義的不適用性

在計算密集的任務中使用基於RESTful的微服務時,所面臨的另外一個維度的挑戰就是HTTP協議相關的語義。從功能的角度來看,如果對一條或數量有限(比如幾百條)的記錄進行事務性操作,那麼HTTP請求是非常匹配的,如下面的表格所示。

軟體設計技術會建議我們暴露一個公開的介面,這個介面反應了底層程式的實際功能,這樣的話,消費者在使用介面的時候就不會有任何的歧義性。在總損失分佈計算的場景中,支援Loss Distribution上下文的微服務應該暴露一個或多個方法,這些方法代表了生成損失分佈的功能,這與CRUD操作是不同的,如下圖所示。所以,從語義上來講,HTTP協議缺乏必要的詞彙來處理那些本質上不是事務性的操作。

(點選放大影象)

圖24

為了進一步闡述這一點,假設與Risk Matrix for Loss Data上下文相關的微服務能夠生成上千條記錄的矩陣,我們暫且不提上百萬條記錄這件事。如前所述,接下來的功能步驟涉及損失分佈的生成。但是,Loss Distribution微服務所提供的操作與風險矩陣所要執行任務存在功能上的不匹配。根據名字,第二個服務所暴露的HTTP方法中,我們找不到一個方法應該包含生成損失分佈的程式碼。圖25描述了Loss Distribution微服務應該暴露的公開介面。

(點選放大影象)

圖25

即使修改第二個微服務的公開介面,以便於更好地反映其功能職責,那也無助於解決將上百萬條記錄從一個微服務轉移至另一個微服務所面臨的挑戰。從技術的角度來看,合適的方案是儘可能減少資料的轉移,所以Hadoop生態系統以及Apache Cassandra是值得深入探討的相關技術。

總而言之,如果每個微服務的資料和功能都能描述清楚,並且它們之間的依賴能夠保持最小,那麼基於微服務的架構可能會執行得非常好,至少它是可控的。只要不嚴格要求ACID特性(CAP理論與最終一致性),OLTP或事務性的系統可能也適用於基於微服務的架構。但是,在涉及到分析領域相關的問題域時,這種架構正規化所帶來的收益將會很難實現。