來自:開源中國

https://www.oschina.net/question/2720166_2283418

今天談到系統架構模式,很難不聯想起微服務架構。企業或組織在系統架構的實踐過程中,從最初的單體架構,之後走向 SOA,逐漸分佈式之後,最終產生了微服務架構。

微服務架構的出現,爲應對快速變化的業務需求、冗長的開發週期提供了一種新的解決方案,它以模塊化的思維應對快速變化的業務需求,解耦系統之間各個子系統、業務、數據庫,甚至開發團隊,使用如自動化部署、自動化業務監控預警、調用鏈監控、容器化,以及敏捷開發等思想加快軟件的開發週期,實現更快速、更高質量的交付,成爲當下最流行的架構風格之一。

微服務架構如此火熱,開發者想要了解其相關知識點,可以通過看書、學習各個公司的實踐經驗,或者請教有經驗的專家,要不就去聽技術會議分享,同時網上也有很多相關理論與實踐總結可以查看。

而我們之前通過網站上“高手問答”這一欄目,爲大家提供了一個集中式向專家提問的機會,讓更多人能夠直接面對專家,提升微服務架構相關能力。當期觀衆提問與專家的回答有許多精彩之處,故整理出此文,以饗讀者。

Q:微服務架構和傳統的 SOA 架構有什麼區別?

面向服務的架構(SOA)是一個組件模型,它將應用程序的不同功能單元(稱爲服務)通過這些服務之間定義良好的接口和契約聯繫起來。接口是採用中立的方式進行定義的,它應該獨立於實現服務的硬件平臺、操作系統和編程語言。這使得構建在各種各樣系統中的服務可以以一種統一和通用的方式進行交互。

都是做服務化,那麼微服務與 SOA 的異同有哪些呢?

相同點

  • 需要 Registry,實現動態的服務註冊發現機制。
  • 需要考慮分佈式下面的事務一致性,CAP 原則下,兩段式提交不能保證性能,事務補償機制需要考慮。
  • 同步調用還是異步消息傳遞,如何保證消息可靠性?SOA 由 ESB 來集成所有的消息。
  • 都需要統一的 Gateway 來匯聚、編排接口,實現統一認證機制,對外提供 APP 使用的 RESTful 接口。
  • 同樣要關注如何再分佈式下定位系統問題,如何做日誌跟蹤?就像電信領域做了十幾年的信令跟蹤的功能。

差異點

  • 是持續集成、持續部署?對於 CI、CD(持續集成、持續部署),這本身和敏捷、DevOps 是交織在一起的,所以更傾向於軟件工程的領域而不是微服務技術本身。
  • 使用不同的通信協議是不是區別?微服務的標杆通信協議是 RESTful,而傳統的 SOA 一般是 SOAP,不過目前來說採用輕量級的 RPC 框架(Dubbo、Thrift、gRPC)非常多,在 Spring Cloud 中也有 Feign 框架將標準 RESTful 轉爲代碼的 API 這種仿 RPC 的行爲,這些通信協議不應該是區分微服務架構和 SOA 的核心差別。
  • 是流行的基於容器的框架還是虛擬機爲主?Docker 虛擬機和物理機都是架構實現的一種方式,不是核心區別。

SOA 和微服務的一個主要不同點就是自動化程度上的不同。大部分的 SOA 實現只達到服務級別的抽象,而微服務達到了對實現和運行環境的抽象級別。

在一個規範的微服務中,每個微服務應該被構建成胖 JAR(fat JAR),其中內置了所有的依賴,然後作爲一個單獨的 Java 進程存在。

Q:微服務業務層如何進行分層?業務系統如何定級,標準爲什麼?

一般微服務的分層需要根據公司的自身情況。

同一公司使用統一應用分層,以減少開發維護學習成本。應用分層看起來很簡單,但每個程序員都有自己的一套方法,哪怕是初學者,所以想實施起來並非那麼容易。

最早接觸的分層架構應該是我們最熟悉的 MVC(Model-View-Controller)架構,其將應用分成了模型、視圖和控制層,可以說引導了絕大多數開發者。而現在的應用(包括框架)中非常多架構設計都使用此模式。之後又演化出了 MVP(Model-View-Presenter)和 MVVM(Model-View-ViewModel)。這些可以說都是隨着技術的不斷髮展,爲了應對不同場景所演化出來的模型。

而微服務的每個架構都可以再細分成領域模型,下面看一下經典的領域模型架構。

它包括了 Domain、Service 和 Repositories。核心實體(Entity)和值對象(Value Object)應該在 Domain 層,定義的領域服務(Domain Service)在 Service 層,而針對實體和值對象的存儲和查詢邏輯都應該在 Repositories 層。

值得注意的是,不要把 Entity 的屬性和行爲分離到 Domain 和 Service 兩層中去實現,即所謂的貧血模型,事實證明這樣的實現方式會造成很大的維護問題。基於這種設計,工程的結構可以構造爲:

關於微服務架構,你需要關注的那些點

當然,在微服務的架構中,每個微服務不必嚴格遵照這樣的規定,切忌死搬硬套,最重要的是理解業務。在不同的業務場合,架構的設計可以適當地調整,畢竟適合的架構一定要具有靈活性。

分層的原則如下:

文件夾分層法

應用分層採用文件夾方式的優點是可大可小、簡單易用、統一規範,可以包括5個項目,也可以包括50個項目,以滿足所有業務應用的多種不同場景。

調用規約

在開發過程中,需要遵循分層架構的約束,禁止跨層次的調用。

下層爲上層服務

以用戶爲中心,以目標爲導向。上層(業務邏輯層)需要什麼,下層(數據訪問層)就提供什麼,而不是下層(數據訪問層)有什麼,就向上層(業務邏輯層)提供什麼。

實體層規約

Entity 是數據表對象,不是數據訪問層對象;DTO 是網絡傳輸對象,不是表現層對象;BO 是內存計算邏輯對象,不是業務邏輯層對象,不是隻能給業務邏輯層使用。如果僅限定在本層訪問,則導致單個應用內大量沒有價值的對象轉換。以用戶爲中心來設計實體類,可以減少無價值重複對象和無用轉換。

U型訪問

下行時表現層是 Input,業務邏輯層是 Process,數據訪問層是 Output。上行時數據訪問層是 Input,業務邏輯層是 Process,表現層是 Output。

Q:微服務的粒度到底怎麼劃分,有什麼經驗嗎?

這個也是個設計問題,首先是業務必須熟悉,然後可以根據領域模型進行領域劃分,拆分可以根據 AKF 擴展立方體(Scalability Cube)。

這個立方體有三個軸線,每個軸線描述擴展性的一個維度,他們分別是產品、流程和團隊:

  • X軸 —— 代表無差別的克隆服務和數據,工作可以很均勻的分散在不同的服務實例上;
  • Y軸 —— 關注應用中職責的劃分,比如數據類型,交易執行類型的劃分;
  • Z軸 —— 關注服務和數據的優先級劃分,如分地域劃分。
關於微服務架構,你需要關注的那些點

三個維度擴展的對比

通過這三個維度上的擴展,可以快速提高產品的擴展能力,適應不同場景下產品的快速增長。不同維度上的擴展,有着不同的優缺點:

X軸擴展

  • 優點:成本最低,實施簡單;
  • 缺點:受指令集多少和數據集大小的約束。當單個產品或應用過大時,服務響應變慢,無法通過X軸的水平擴展提高速度;
  • 場景:發展初期,業務複雜度低,需要增加系統容量。

Y軸擴展

  • 優點:可以解決指令集和數據集的約束,解決代碼複雜度問題,可以實現隔離故障,可以提高響應時間,可以使團隊聚焦更利於團隊成長;
  • 缺點:成本相對較高;
  • 場景:業務複雜,數據量大,代碼耦合度高,團隊規模大。

Z軸擴展

  • 優點:能解決數據集的約束,降低故障風險,實現漸進交付,可以帶來最大的擴展性。
  • 缺點:成本最昂貴,且不一定能解決指令集的問題;
  • 場景:用戶指數級快速增長。

如何將理論付諸實踐?

爲擴展分割應用

  • X軸:從單體系統或服務,水平克隆出許多系統,通過負載均衡平均分配請求;
  • Y軸 :面向服務分割,基於功能或者服務分割,例如電商網站可以將登陸、搜索、下單等服務進行Y軸的拆分,每一組服務再進行X軸的擴展;
  • Z軸 :面向查找分割,基於用戶、請求或者數據分割,例如可以將不同產品的SKU分到不同的搜索服務,可以將用戶哈希到不同的服務等。

爲擴展分割數據庫

  • X軸:從單庫,水平克隆爲多個庫上讀,一個庫寫,通過數據庫的自我複製實現,要允許一定的讀寫時延;
  • Y軸 :根據不同的信息類型,分割爲不同的數據庫,即分庫,例如產品庫,用戶庫等;
  • Z軸 :按照一定算法,進行分片,例如將搜索按照MapReduce的原理進行分片,把SKU的數據按照不同的哈希值進行分片存儲,每個分片再進行X軸冗餘。

爲擴展而緩存

在理想情況下,處理大流量最好的方法是通過高速緩存來避免處理它。從架構層面看,我們能控制的主要有以下三個層次的緩存:

  • 對象緩存:對象緩存用來存儲應用的對象以供重複使用,一般在系統內部,通過使用應用緩存可以幫助數據庫和應用層卸載負載。
  • 應用緩存:應用緩存包括代理緩存和反向代理緩存,一個在用戶端,一個在服務端,目標是提高性能或減少資源的使用量。
  • 內容交付網絡緩存:CDN 的總原則是將內容推送到儘可能接近用戶終端的地方,通過不同地區使用不同ISP的網關緩存,達到更快的響應時間和對源服務的更少請求。

爲擴展而異步

  • 同步改異步:同步調用,由於調用間的同步依賴關係,有可能會導致雪崩效應,出現一系列的連鎖故障,進而導致整個系統出現問題,所以在進行系統設計時,要儘可能的考慮異步調用方式,郵件系統就是一個非常好的異步調用例子。
  • 應用無狀態:當進行 AKF 擴展立方體的任何一個軸上的擴展時,都要首先解決應用的狀態問題,即會話的管理,可以通過避免、集中和分散的方式進行解決。

Q:微服務怎麼實現事務管理的?

其實微服務的事務就是分佈式事務,剛性事務和柔性事務。

剛性事務是指嚴格遵循 ACID 原則的事務,例如單機環境下的數據庫事務。柔性事務是指遵循 BASE 理論的事務,通常用在分佈式環境中,常見的實現方式有:兩階段提交(2PC),TCC 補償型提交,基於消息的異步確保型,最大努力通知型。

數據一致性分爲以下幾種情況:

強一致性

當更新操作完成之後,任何多個後續進程或者線程的訪問都會返回最新的更新過的值。這種是對用戶最友好的,就是用戶上一次寫什麼,下一次就保證能讀到什麼。根據 CAP 理論,這種實現需要犧牲可用性。

弱一致性

系統並不保證後續進程或者線程的訪問都會返回最新的更新過的值。系統在數據寫入成功之後,不承諾立即可以讀到最新寫入的值,也不會具體地承諾多久之後可以讀到。

最終一致性

弱一致性的特定形式。系統保證在沒有後續更新的前提下,系統最終返回上一次更新操作的值。在沒有故障發生的前提下,不一致窗口的時間主要受通信延遲、系統負載和複製副本的個數影響。DNS 是一個典型的最終一致性系統。

分佈式事務的各種實現方式:

  • 如果業務場景需要強一致性,那麼儘量避免將它們放在不同服務中,也就是儘量使用本地事務,避免使用強一致性的分佈式事務。
  • 如果業務場景能夠接受最終一致性,那麼最好是使用基於消息的最終一致性的方案(異步確保型)來解決。
  • 如果業務場景需要強一致性,並且只能夠進行分佈式服務部署,那麼最好是使用 TCC 方案而不是 2PC 方案來解決。

Q:在基於 Spring Cloud 的微服務架構中,使用 Docker 和 k8s 這些容器化技術能帶來哪些方面的好處?對於中小規模的微服務架構中,是否有使用它們的必要性呢?

容器技術不是模仿硬件層次,而是在 Linux 內核裏使用 cgroup 和 namespaces 來打造輕便的、將近裸機速度的虛擬技術操作系統環境。因爲不是虛擬化存儲,所以容器技術不會管底層存儲或者文件系統,而是你放哪裏,它操作哪裏。

也就是說,它能更細粒度地控制 Linux,能夠做到按需分配,我們企業級開發種經常面臨的一個問題就是資源不足,而使用 Docker 可以更加有效地利用資源。這個跟企業的規模個人感覺不是很大。

Q:微服務模式下數據庫的管理,多個服務之間的數據聚合怎麼做才能避免數據過於分散導致查詢實現困難?感覺 k8s 可以代替 Spring Cloud 的一些組件(比如均衡負載、配置服務、服務發現),如何才能分清它們之間的關係?

數據聚合其實涉及到微服務的一種設計模式,微服務的設計模式主要有以下幾種:鏈式設計模式、聚合器設計模式、數據共享設計模式和異步消息控制模式。

聚合器設計模式是將請求統一由網關路由到聚合器,聚合器向下路由到指定的微服務中獲取結果,並且完成聚合。首頁展現、分類搜索和個人中心等通常都使用這種設計。

關於微服務架構,你需要關注的那些點

數據共享模式也是微服務設計模式的一種。應用通過網關調用多個微服務,微服務之間的數據共享通過同一個數據庫,這樣能夠有效地減少請求次數,並且對於某些數據量小的情況非常適合。

關於微服務架構,你需要關注的那些點

也就是說,服務需要經過一定的設計處理。可以再網關部分實現數據查詢的路由。

說到 k8s 和 Spring Cloud,兩個平臺在覈心領域都很強,並且在其它領域改進。Spring Cloud 可以快速使用、對開發者友好,然而 Kubernetes 對 DevOps 友好,艱難的學習曲線,但是覆蓋更廣泛的微服務障礙。以下是這些點的總結。

關於微服務架構,你需要關注的那些點

兩種架構處理了不同範圍的 MSA 障礙,並且它們從根本上用了不同的方法。Spring Cloud 方法是試圖解決在 JVM 中每個 MSA 挑戰,而 Kubernetes 方法是試圖讓問題消失,爲開發者在平臺層解決。Spring Cloud 在 JVM 中非常強大,Kubernetes 管理那些 JVM 很強大。同樣的,它就像一個自然發展,結合兩種工具並且從兩個項目中最好的部分受益。

Q:請教一下,關於微服務架構中的 Service Mesh,它有哪些優勢呢?

Service Mesh 最終並不是引入一項新功能,而是功能定位的轉變。首先我們要知道 Web 應用程序總是必須管理服務間通信的複雜性。

Service Mesh 是一個網絡模型,它是位於 TCP/IP 之上的抽象層,它假定底層的 L3/L4 網絡是真實存在的,並且能夠點對點地傳遞字節。但與 TCP 不同的是,Service Mesh 具有更高的性能。

它以專用基礎設施層的形式存在,通常作爲一組輕量級高性能網絡代理,這些代理和程序代碼部署在一起,但是應用程序不需要對代理有任何動作,它被用來處理服務間通訊,通過複雜的拓撲結構讓請求傳遞的過程變得更可靠。

你可以思考下2000年的中型 Web 應用程序的典型架構: 三層應用程序。 在這個模型中,應用程序邏輯、Web 服務邏輯和存儲邏輯都是單獨的一層,層之間的通信雖然複雜,但這種複雜性是限定在一定範圍內,因爲畢竟只有兩個跳轉。這裏沒有“網格”(Mesh),但是在每個層的代碼中處理的跳轉之間有通信邏輯。

當這種架構方式在面對應用程序內部邏輯越來越複雜化的情形時,它就開始崩潰了。 像 Google、Netflix 和 Twitter 這樣的公司無時無刻都面臨着巨大的流量需求,它們實現了雲原生方案的前身:應用層被分解成許多服務(有時稱爲“微服務”),層級間則形成了一個拓撲結構。

在這些系統中,廣義的通訊層突然變得相關起來,但通常以“胖客戶端”的庫集(library)形式出現, 比如 Twitter 的 Finagle、Netflix 的 Hystrix,以及 Google 的 Stubby 就是這樣的例子。

從很多方面上來講,像 Finagle、Stubby 和 Hystrix 這些庫集其實是 Service Mesh 的雛形。雖然它們受其周圍環境的細節影響,並且需要使用特定的語言和框架,但是它們是用於管理服務到服務間通信的專用基礎設施,並且(在開源 Finagle 和 Hystrix 庫集的情形下)可以在其公司之外使用。

到了雲原生應用時期,雲原生模型本身結合了許多小型服務的微服務方法和兩個額外的因素:容器(例如 Docker),它提供了資源隔離和依賴關係管理,以及一個編排層(例如 Kubernetes),它將底層硬件抽象出了一個同質池。

這三個組件支持應用程序在負載下可彈性伸縮的自然機制, 並能夠處理雲平臺環境中存在的部分故障。

但面對數百個服務或數千個實例,和隨時在重新安排實例的編排層,單個請求經由服務拓撲的路徑可能非常複雜,而由於容器使每個服務用不同的語言寫入處理變得更容易了,庫集方法也就不再可行了。

這種複雜性和關鍵性的結合,激發了對服務到服務間通信的專用基礎層的需求,這個專用層與應用程序代碼分離出來,並能夠捕捉底層環境的高度動態特性。就是這一專用層我們稱之爲 Service Mesh。這樣 Service Mesh 的優勢自然也就可以瞭解了。

Q:我是來自於一家中小企業的運維和開發人員,一直對微服務架構很感興趣,請問一下如果我們企業將來打算採用微服務架構,我們將面臨着哪些挑戰?

面臨的挑戰:

  • 思想的轉變。首先要徹底地理解什麼是微服務,要知道它相比單體架構、SOA 架構的不同是什麼、優劣是什麼,具體如何落地等問題。
  • 新技術以及新框架的學習。比如spring boot、docker等。

一些建議:

  • 通過查閱相關資料,對傳統架構和微服務架構的區別以及演變流程,可以首先有一個概念性的瞭解。
  • 可以先讓一部分人使用微服務架構並且做到深入的程度,然後再在企業中整體推廣。
相關文章