2018年,每一個人都據說過微服務。但你知道怎麼設計嗎?前端
微服務是當今軟件工程師的一個熱門話題。讓咱們瞭解如何使用微服務架構風格構建真正模塊化、業務敏捷的IT系統。數據庫
1、微服務概念編程
微服務體系結構由輕量級、鬆散耦合的服務集合組成。每一個服務都實現了單個業務功能。理想狀況下,這些服務應該是具備足夠的內聚性,能夠獨立地開發、測試、發佈、部署、擴展、集成和維護。後端
正式定義 設計模式
「微服務架構風格是一種將單個應用程序開發爲一組小型服務的方法,每一個小服務運行在本身的進程中,而且以輕量級機制(一般是HTTP REST API)通訊。這些服務是圍繞業務能力創建的,而且能夠由徹底自動化的部署機構獨立部署。這些服務的集中管理只有最低限度,能夠用不一樣的編程語言編寫並使用不一樣的數據存儲技術。」緩存
—— James Lewis and Martin Fowler安全
定義微服務的特性服務器
每一個服務都是一個輕量級、獨立和鬆散耦合的業務單元。網絡
每一個服務都有本身的代碼庫,由一個小團隊管理和開發(主要是用於敏捷環境中)。架構
每一個服務負責一部分功能或者說業務能力,而且作得很好。
每一個服務均可覺得其用例選擇最佳的技術棧(無需將整個應用程序綁定在一個框架中)。
每一個服務都有本身的DevOps計劃(測試、發佈、部署、擴展、集成和獨立維護)。
每一個服務都部署在一個獨立自給的環境中。
服務經過使用定義良好的API(智能端點)和簡單協議如基於HTTP 的REST協議(啞管道)相互通訊。
每一個服務負責持久化本身的數據和保持外部狀態(只有當多個服務使用相同的數據時,這種狀況纔在公共數據層中處理)。
白小白:
智能端點和啞管道,其實我一直認爲「啞」管道不如「笨」管道或者「呆」管道更易理解。防呆設計是一種預防用戶錯誤使用產品形成不良後果的設計理念,好比USB設計成一半有實體芯片,就是讓用戶能夠不假思索的在插錯後直接掉轉方向再插。不讓用戶思考就是「呆」的含義。「啞」管道的「啞」其實就是體如今微服務的通訊過程儘可能簡單,不要讓通訊機制有「思考能力」,不在其中加入過多的處理機制,反例是SOA時代的ESB產品,ESB產品一般會包含複雜的設施用於消息路由,編排和轉換,以及業務規則應用。反過來,智能端點的概念就容易理解了,也就是將與某服務相關的處理都限定在微服務的範疇以內,通訊過程當中的微服務端點是「智能」的,這也從一個方面體現了微服務「高內聚」的含義,有了高內聚,才能具有自治和獨立性,從而能夠支持「鬆耦合」的機制。
微服務的好處
微服務能夠用於擴展大型系統,也爲持續集成和交付提供了巨大的能力。
Scale Cube:用於可伸縮性的三維模型
(圖片:Nginx博客)
獨立縮放:《 The Art of Scalability》( http://t.cn/EAvlQ4o)這本優秀的書中所描述的Scale Cube概念,是微服務架構所支持的。在開發微服務以實現功能分解時,應用程序經過Y軸自動縮放。當服務調用量較高時,微服務能夠經過克隆更多的CPU和內存,經過X軸進行擴展。爲了在多臺機器上分發數據,能夠分離大型數據庫(分庫分表)轉換成更小、更快、更容易管理的部件,從而實現Z軸的縮放。
獨立發佈和部署:使用微服務,Bug修復和特性發布更易於管理,風險更小。能夠在不從新部署整個應用程序的狀況下更新服務,並在出現問題時回滾或前滾更新。
獨立開發:每一個服務都有本身的代碼庫,由一個小的焦點小組開發、測試和部署。開發人員能夠專一於一種服務,而且只關注相對較小的範圍。這將提升生產率、項目速度、持續創新能力和源碼質量。
優雅降級:若是服務崩潰,其影響不會傳播到應用程序的其餘部分,並致使系統發生災難性故障,從而體現某種程度的健壯性。
分散治理:開發人員能夠自由選擇技術棧,制定最適合其服務的設計標準和實現決策。團隊沒必要由於過去的技術決定而受到懲罰。
業務關切
獨立的服務自己並不能造成一個系統。要使微服務體系結構真正成功,須要大量投資來處理跨系統的問題,例如:
服務複製:一種讓服務易於擴展的基於元數據的機制
服務註冊和發現:啓用服務查找並查找服務端點的機制
服務監測和日誌:收集來自不一樣微服務的日誌的機制,並提供一致的報告
彈性:服務在故障期間自動採起糾正行動的機制
DevOps:處理持續集成和部署的機制(CI和CD)
API網關:爲客戶端提供入口的機制
2、中間件與設計模式
API網關(全部客戶端的單一入口點)
API網關風格的微服務體系結構(圖片來自:Microsoft Azure Docs),是用於微服務的最多見的設計模式。API網關是一箇中間層,具備最小化的路由功能,只是充當一個「啞管道」,裏面沒有業務邏輯。通常來講,API網關容許客戶端基於REST/HTTP調用託管的API。其餘類型的微服務集成模式有:點對點風格(直接從客戶端應用程序調用服務)和消息代理風格(實現異步消息傳遞)。
API網關充當全部客戶端的單一入口點,API網關也做爲一種邊緣服務來將微服務做爲託管API公開給外部世界。這聽起來像是一個反向代理,但也有一些額外的責任,例如簡單的負載平衡,認證和受權,故障處理,審覈,協議轉換,和路由機制。開發團隊能夠選擇如下方法之一來實現API網關。
本身編程實現:具備更好的客戶化和管控能力。
部署現有的API網關產品:節省初始開發時間,並使用高級內置功能(缺點在於:此類產品依賴於供應商,並不徹底免費。配置和維護一般是冗長而耗時的)
解釋API網關行爲的一些設計模式以下(請參閱微服務設計模式 http://t.cn/RKx8bhG).
網關聚合(http://t.cn/EAvT2jl):將針對多個內部微服務的多個客戶端請求(一般是HTTP請求)聚合到單個客戶端請求中,減小了使用者和服務之間的交互和網絡延遲。
網關分流(http://t.cn/EAvTGmA):使單個微服務可以將一些共享的服務功能分流到API網關級別。這些跨服務功能包括認證、受權、服務發現、容錯機制、QoS、負載平衡、日誌記錄、分析等。
網關路由(第7層路由,一般是HTTP請求 http://t.cn/EAvTMm4):使用單一入口端點將請求路由到內部微服務的端點,這樣服務調用者就不須要自行管理多個獨立的端點
請注意,API網關應該始終是一個高可用性和高性能的組件,由於它是整個系統的入口點。
事件總線(用於異步事件驅動通訊的、發佈/訂閱、中介通道)
微服務之間基於事件驅動的異步通訊實現最終一致性
(圖片來源:microsoft.com)
應用程序的不一樣部分在進行相互通訊時,不管消息的順序(爲處理異步的消息)或使用的語言(爲了體現語言無關性),均可以使用事件總線來實現。大多數事件總線支持發佈/訂閱、分佈式、點對點和請求響應消息傳遞。一些事件總線(如Vert.x)容許客戶端使用相同的事件總線與相應的服務器節點進行通訊,這是全堆棧團隊所喜好的一個很酷的特性。
服務網格(用於服務間通訊的外掛(Sidecar)機制)
服務網格風格的服務間通訊
(圖片來源:微服務實踐http://t.cn/EAAJWRi)
如何在應用程序中使用服務網格
(圖片來源:http://t.cn/EAAizgn)
服務網格經過提供服務間通訊的輔助架構來實現外掛模式,包括彈性(容錯、負載平衡)、服務發現、路由、可觀察性、安全性、訪問控制、通訊協議支持等功能。
服務網格在網絡堆棧中的位置
(圖片來源:http://t.cn/EAAizgn)
實際上,外掛實例部署在每一個服務的旁邊(理想狀況下是在同一個容器中)。他們能夠經過服務自己的網絡功能來進行通訊。服務網格的控制平面被單獨部署,以提供中心功能,如服務發現、訪問控制和可觀察性(監視、分佈式日誌記錄)。最重要的是,服務網格風格的設計模式容許開發人員從微服務代碼中分離網絡通訊功能並使服務只關注於業務功能。(來自:Netflix Prana, 微服務網格)
儘管上面的圖片顯示了服務之間的直接鏈接,可是處理服務間通訊的好方法是使用一個簡單的事件總線做爲中介,以保持最低級別的耦合。
在API網關級別上實現BFF模式和聚合器模式
(圖:microsoft.com)
若是應用程序須要裁剪每一個API以適應客戶端應用程序類型(Web端、移動端以及其餘不一樣平臺),則能夠經過聚合器(Aggregator)執行不一樣的業務規則,也能夠執行不一樣的配置以根據客戶端功能適配不一樣的構建。這能夠在API網關級別實現,也能夠在服務級別並行實現。這種模式對於提供特定的用戶體驗很是有用。可是,開發團隊應該足夠當心,將BFF保持在可管理的範圍內。
白小白:
「經過聚合器」,原文是「via a facade」,直譯是「經過一個外觀/門面」。門面模式(外觀模式),是一種Java的設計模式,爲子系統中的一組接口提供了一個統一的訪問接口,引伸自一個前店後廠的生意模式,前面是門面,後面會有進料、生產、包裝多個服務。用在這裏是指將相關的服務經過聚合器聚合在一塊兒,這個聚合器就是門面。服務調用者與門面交互而不是與一組服務交互下降了耦合性,但同時違反了面向對象設計原則開閉原則,開閉原則要求模塊在擴展時能夠不改動內部的代碼,但顯然當聚合器後端的某個服務發生變動時,須要在聚合器層面也發生變動,這也是文中說「開發團隊應該足夠當心」的緣由,由於違反了開閉原則,就會下降可複用性。
3、最佳實踐
✅ 領域驅動設計:圍繞業務領域進行服務建模。
爲了處理大型模型和團隊,能夠應用領域驅動設計(DDD)。DDD經過將大型模型劃分爲不一樣的有界上下文來明確他們之間的相互關係和子領域。這些有界上下文能夠在應用設計級別轉換爲單獨的微服務。(參見:領域驅動設計中的有界上下文 http://t.cn/EAAK4Xk)
✅ 分散數據管理(避免共享數據庫):當多個服務使用一個共享數據架構時,會在數據層造成緊耦合。爲了不這種狀況,每一個服務都應該有本身的數據存取邏輯和獨立數據存儲。開發團隊能夠根據服務和數據性質的不一樣自由選擇最適合的數據持久性方法。
避免共享數據存儲和訪問機制
(圖片來源:http://t.cn/RcLB5Kv)
✅ 智能端點和啞管道:每一個服務都擁有一個定義良好的外部通訊API,並儘可能避免泄露實現細節。通訊則始終使用簡單協議,如基於HTTP的REST協議。
✅ 異步通訊:當跨服務使用異步通訊時,其餘服務不會阻塞數據流。
同步消息和異步消息傳遞
(來源: http://t.cn/EAA9xRU)
✅ 避免服務耦合:服務應保持鬆耦合和高內聚。產生耦合的主要緣由包括共享數據庫模型和嚴格的通訊協議。
✅ 分散開發:避免在多個服務/項目之間共享代碼庫、數據架構或開發團隊成員。讓開發者從源頭上關注創新和質量。
✅ 將領域知識排除在網關以外:讓網關處理路由和跨服務問題(如身份驗證、SSL終端等)。
✅ 基於令牌的認證:不要在每一個微服務級別實現安全組件,由於這將須要組件與集中式/共享用戶存儲庫對話並檢索身份驗證信息;而是考慮實現API網關級別的身份驗證,使用普遍使用的API安全標準,如OAuth2和OpenID Connect。一旦從認證提供者得到令牌以後,就能夠用於與其餘微服務進行通訊。
使用OAuth2和OpenID Connect的微服務安全性
(來源:Kasun’s Blog http://t.cn/EAACGvY)
✅ 事件驅動性質:既然人能夠成爲對事件做出反應的自主主體,系統也能夠。(參見:爲何微服務應該是事件驅動的:自主性與權威性 http://t.cn/EAACWOx)
✅ 最終一致性:因爲微服務的高內聚特性,很難在整個系統內實現很強的一致性。所以開發團隊必須處理最終一致性。
✅ 容錯:因爲系統由多個服務和中間件組成,所以在某些地方可能很容易發生故障。對於這些薄弱環節,有一些實現模式,如斷路器,防水艙,重試,超時,快速失敗,故障轉移緩存,速率限制,負載釋放,能夠將重大故障的風險降到最低。(參見:設計一種面向故障的微服務體系結構http://t.cn/RChKlg9)
✅ 產品工程化:把微服務工程化爲一種產品,而不是做爲一個項目,可讓微服務更好的發揮做用。這意味着,不能僅僅考慮能用並且及時交付,而是要長期致力於卓越的工程化。
4、微服務實踐
什麼時候使用微服務
微服務架構最適合的應用場景:
具備高可伸縮性需求的應用
對交付速度要求較高的項目
具備豐富域或多個子域的業務用例
小型、跨功能的開發團隊協做開發大型產品的敏捷環境(請參閱:微服務架構的真正成功故事 http://t.cn/EAANng7)
一些實現微服務的入門框架
Vert.x:輕量級,易於理解/實現/維護,多語言支持(支持多種語言),事件驅動,非阻塞,能夠說,具有了以最少的硬件處理高併發需求時的最佳性能和可伸縮性,而且具有足夠的開放性(與傳統的限制性框架不一樣,Vert.x只提供有用的組件,開發人員能夠自由地創新並仔細構建他們的應用程序)
Akka:使人滿意的性能,實現了Actor模型(一種併發模型),有利於響應式微服務和事件驅型微服務
Spring Boot/Spring Cloud:容易上手(採用熟悉範式),基於良好的舊Spring框架,有點重的框架,許多集成可用,大規模的社區支持
Drop Wizard:有利於RESTful Web服務的快速開發,它搭載了一些不錯的Java工具和庫,如Google Guava、Jetty Server、Logback、Hibernate Validator、Joda Time、Jersey和Jackson。
部署選項
容器:有利於執行DevOps目標(快速開發,縮短上市時間,無縫縮放)
雲計算架構:有利於構建可靠和可伸縮的基礎設施,爲地理位置分散的用戶服務。
無服務器架構:適合處理高度不穩定的流量。
維護本身的IT基礎設施:對那些擁有足夠能力和資源建設整個基礎設施的組織來講是件好事。
微服務的開發理念
自給系統:由獨立系統組裝軟件(按業務垂直切分系統)
微前端:將單體應用的Web UI劃分爲獨立的特性,這些特性能夠做爲獨立的UI組件開發,並直接與微服務進行通訊。
須要搜索和學習的關鍵詞
領域驅動設計(DDD)| 有界上下文(BC)| 聚合持久性(PP)| 命令和查詢責任隔離(CQRS)| 命令查詢分離(CQS)| 事件溯源(ES)| CAP定理 |最終一致性 |十二要素應用 |SOLID原則 |
5、參考架構
用於在線購物應用程序的微服務體系結構
(圖片:microsoft.com)
此體系結構是由使用Microsoft技術的Microsoft開發人員提出的。在這裏,API Gateway是針對不一樣的Web和移動用戶而定製的。對於數據層,數據存儲技術是根據業務功能仔細選擇的(關係數據庫用於結構化數據,Redis用於臨時數據緩存,MongoDB和Cosmos DB用於非結構化數據)。事件總線處理服務間通訊。撇開技術不說,這是基於微服務的應用最多見的集成模式。
一種非阻塞應用程序的微服務體系結構,該應用程序使用來自各類事件源(例如交通數據、天氣指數、股票市場線索、社交媒體帖子、傳感器輸出)的大量輸入數據流來向最終用戶顯示實時更新。這些輸入數據流最初由使用Kafka實現的事件日誌收集。它將數據保存在磁盤上,所以能夠用於批處理調用(分析、報告、數據科學、備份、審計)或用於實時調用(運營分析、CEP、管理儀表板、警報應用程序)。上圖中,使用Spark按指定的時間間隔,將持續的輸入數據流劃分爲微批次,並輸入到WSO2 Siddhi CEP引擎中。後者標識事件並使用MongoDB存儲以非結構化形式存儲數據。微服務調取這些數據並顯示給最終用戶。仔細觀察這一設計, Vert.x事件總線可以建立與前端UI組件的鏈接,該特性僅用於有效地更新UI中的相關部分。撇開技術不說,這是基於事件驅動的非阻塞微服務應用程序的一個很好的架構。
用於訂單管理應用程序的雲原生泛渠道微服務體系結構(圖片:ibm.com)這個設計的一個主要特色是,IBM架構師沒有使用API網關,而是爲每一個客戶端通道(移動應用程序、Web應用程序、IOT設備、API使用者)提出了一個具備獨立後端的邊緣層。另外一個特色是將微服務層劃分爲業務邏輯層和基礎層兩個子層。基礎層(即核心服務層)使用各類雲原生服務(雲數據存儲、集成和索引Watson會話的Elastic搜索引擎)處理持久化和集成任務。業務邏輯層集成了基礎層的數據,並提供了有意義的業務功能。這將是一個很好的架構,能夠爲地理上分散的大量用戶羣提供服務,並經過各類平臺訪問應用程序。