1. 程式人生 > >詳解微服務實踐 從架構到部署

詳解微服務實踐 從架構到部署

文章來自微信公眾號:DevOps研究院

前言:

前段時間公司事情多,這篇長文寫了放、放了寫…耽擱了一些進度。各個自媒體的更新也慢了很多,這裡給大家說句抱歉了。

現如今“微服務”遍地開花,已經成軟體架構領域最受歡迎的熱門話題之一。網上和書籍中都有很多關於微服務基礎和優勢的學習材料,但是我們可能會發現這東西在現實世界企業場景中似乎好像沒那麼普及,真正能跑的微服務資源其實也不是很多,大多是停留在概念和摸索階段。

在這篇文章裡,我打算講講微服務架構(MSA)的關鍵架構概念,以及如何在實踐中將這些架構原理應用起來。

前因:單片結構

企業應用,因為服務於眾多業務需求,因此會有些特定的軟體應用提供許多功能,而一般慣例是把這些功能都堆在單個單片應用中。例如,ERP,CRM和其他各種軟體系統被規劃構建為具有數百個功能的整體。這種帶坑應用一經部署,在往後的故障排除、擴充套件和升級場景中就是一場接一場的惡夢了。

面向服務架構(SOA)旨在通過引入“服務”的概念來克服以上的限制,“服務”是從應用程式提供的類似功能中提取出來的聚合和分組。因此,使用SOA,軟體應用程式就會被設計為“粗粒度”服務的組合。然而,SOA中服務的範圍非常廣泛,這又引出了複雜而龐大的服務與一大堆操作(功能)以及複雜無比的訊息格式和標準(如WS *標準)。

SOA

多數情況下,SOA中的服務彼此獨立,只不過它們與所有其他服務一起部署在相同的執行時間裡(只需考慮將部署到同一個Tomcat例項中的多個Web應用)。和單片軟體應用類似,這些服務通過積累各種功而具有隨時間推移的習慣。圖1是一個非常好的一個單片架構的例子,顯示了包括多個服務的零售軟體應用,所有這些服務都能部署到同一應用程式。

說了那麼多,大家是不是有點不明所以?我總結了一些重點,以下就是基於單片架構的應用程式的一些特性歸納:

  • 單片應用程式被設計、開發和部署為單個單元。
  • 單片應用相對複雜,導致維護,升級和新特性困難重重。
  • 難以用單片架構來實踐敏捷開發和交付方法。
  • 想更新某部分,很可能要重新部署整個應用。
  • 規模需求衝突的情況下,若想做單點擴充套件,要做好多倍資源甚至推倒重來的準備(例如,想給A服務更多CPU,B服務可能要重做,也可能要補兩三倍memory)
  • 可靠性:一個不穩定的服務可以拖慢整個應用效能。
  • 難創新:採用新技術和框架非常困難,因為所有的功能必須建立在均勻的技術/框架上。

單片架構的天然特性,直接給微服務架構的異軍突起帶來了絕佳的機會。

後果:微服務架構

微服務架構(MSA)的基礎是將單片應用作為一套小型和獨立服務來開發,這些服務都在自己的空間獨立開發、部署和執行。在微服務體系結構的大多數定義中,它普遍被解釋為將巨大的可用服務隔離成一套獨立服務的過程。不過我對這些有自己的理解,微服務的邏輯不僅是將整個大容量服務分為獨立服務,關鍵在於通過檢視從整體提供的功能,我們就可以確定所需的業務能力。而這些業務能力可以具體實現為各自獨立的細粒度和自包含(微)服務。它們可能在一個技術堆疊上實現,每個服務都處理一個非常具體和有限的業務範圍。

 

因此,上面解釋的線上零售系統場景可以通過如圖2的微服務架構實現。通過微服務架構,零售軟體應用程式被規整為一套微服務。而且從圖2最底下一層可以看出,根據業務需求,還多了一個從原始服務組合中額外建立的一個微服務。換句話說,想跟進微服務,要有超大容量服務可能會分裂的準備,不過我相信相比於進步,這點麻煩值得付出。

微服務架構

所以,鋪墊了那麼多,現在我們深入瞭解微服務的關鍵架構原理,這裡重要的是最好帶著實踐的思路來思考問題。

設計微服務:大小,範圍和功能

通過Microservices Architecture可以從頭開始構建軟體應用或改造現有應用程式/服務…無論是哪種方法,正確判定Microservices的大小,範圍和功能,都至關重要。我感覺,這可能是在Microservices Architecture實踐最初(對的,“最初”這個詞用的沒錯)最難的事了。

現在聊聊關於微服務的規模、範圍和功能的關鍵實踐問題和對一些坊間誤解的闢謠。

  1. 程式碼行數/團隊規模都是坑B指標:這裡先引入一個概念,雙披薩團隊,有興趣的可以去深入瞭解。根據實施程式碼或團隊規模,有幾個討論決定了Microservices的大小。然而,這些被認為是非常不切實際和糟糕的指標,即便我們仍然可以使用較少的程式碼/雙比薩團隊做規模開發,但這種思路完全違反了微服務架構主體。
  2. ‘Micro’有點誤導性的詞語:大多數開發人員傾向於認為他們應儘可能的減少服務,這是一個天然的誤解。
  3. 在SOA上下文中,服務通常被實現為具有數十個操作/功能的單片全域性。所以,像SOA這樣的服務就算命名為微服務,不會給你帶來微服務架構的好處。

那麼那麼我們應該如何在微服務架構中正確設計服務?

微服務設計指南

  1. 單一責任原則(SRP):為微服務提供有限和重點突出的業務範圍,有助於我們滿足開發和提供服務的敏捷性。
  2. 在微服務的設計階段,我們應該找到各服務的邊界,並將其與業務能力(也稱為域驅動設計中的有界環境 )保持一致。
  3. 微服務設計要確保敏捷/獨立開發和部署服務的絲滑穩定。
  4. 我們的重點應該放在微服務的範圍上,而不是使服務更”小”。服務的大小應該是指所需的範圍大小,以促進給定的業務能力。
  5. 與SOA中的服務不同,給定的微服務應該具有很少的操作/功能和簡單的訊息格式。
  6. 隨著時間的推移,首先開始具有相對廣泛的服務邊界,重構到較小的服務界限(基於業務需求),這是一個很好的做法。

在我們的零售用例中,整體功能分為四個不同的微服務,即“庫存”,“會計”,“運輸”和“儲存”。他們正在解決一個有限但重點突出的業務範圍,使每個服務彼此完全脫鉤,並確保開發和部署中的敏捷性。

微服務中的訊息傳遞

在單片應用中,使用函式呼叫或語言級方法呼叫不同處理器/元件的業務功能。在SOA中,這種轉移趨向於更為鬆散耦合的Web服務級別訊息傳遞,主要基於不同協議(如HTTP,JMS)之上的SOAP。而具有數十種操作和複雜訊息模式的Web服務是Web服務普及的關鍵阻力。對於Microservices架構,它需要簡單而輕量的訊息傳遞機制就行。

同步訊息 – REST,Thrift

對於同步訊息傳遞(客戶端期望從服務及時得到響應並等待到達),在微服務體系結構中,REST是主流標配,因為它提供了基於資源API風格的HTTP請求響應實現的簡單訊息傳遞方式。因此,大多數微服務實現都使用HTTP以及基於資源API的風格(每個功能都以資源和在這些資源之上執行的操作來表示)。

REST

另外,Thrift (可以在其中為微服務定義介面定義)可以作為REST / HTTP同步訊息傳遞的替代方法。

非同步訊息 – AMQP,STOMP,MQTT

對於某些需要使用非同步訊息傳遞技術(客戶端不期望立即響應或根本不接受響應)的微服務場景。多看看諸如AMQP, STOMP或MQTT之類的非同步訊息協議就好了。

訊息格式 – JSON,XML,Thrift,ProtoBuf,Avro

決定微服務最適合的訊息格式是另一個關鍵因素。傳統單片應用使用二進位制格式(習慣了,表示還好不算複雜);基於SOA / Web服務的應用使用基於複雜訊息格式(SOAP)和模式(xsd)的文字訊息。而在大多數基於微伺服器的應用中,簡單基於文字的訊息格式即可,如JSON和XML,反正就是基於HTTP資源API風格跑起來。在我們需要二進位制訊息格式的情況下(文字訊息在某些用例中可能會變冗長),微服務可以利用二進位制訊息格式,如Thrift,ProtoBuf或Avro…

服務合同 – 定義服務介面 – Swagger, RAML, Thrift IDL

若你把業務能力實現為服務,就需要定義和釋出服務合同。傳統單片應用幾乎找不到這樣的功能來定義應用的業務功能。在SOA/Web服務的世界裡,WSDL用於定義服務合同。不過眾所周知,WSDL不是用於定義微服務合同的理想解決方案,因為WSDL非常複雜且與SOAP緊密耦合。

由於我們在REST架構風格之上構建微伺服器,所以我們可以使用相同的REST API定義技術來定義微伺服器的合同。因此,微服務更多情況下用標準的REST API定義語言(如Swagger和RAML) 來定義服務契約。

對於不基於HTTP/REST(如Thrift)的其他微服務實現,可以用協議級別的“介面定義語言(IDL)”(如Thrift IDL)。

整合微服務(Inter-service / process communication)

在微服務架構中,軟體應用程式被構建為一套獨立的服務。因此,為了實現業務用例,需要在不同的微服務/流程之間建立通訊結構。這就是為什麼微服務之間的服務間/過程通訊至關重要的原因。

在SOA實現中,服務之間的服務間通訊通過企業服務匯流排(ESB)來實現,大部分業務邏輯都位於中間層(訊息路由,轉換和業務流程)中。然而,微服務架構促進消除中央訊息匯流排/ESB,並將“智慧”或業務邏輯移至服務和客戶端(稱為“智慧端點”)。

由於微服務使用諸如HTTP,JSON等標準協議,因此在微服務之間的通訊中,與不同協議整合的要求是最小的。Microservice通訊中的另一種替代方法是使用輕量級的訊息匯流排或閘道器,它們有最小的路由功能,並且僅用作在閘道器上實現業務邏輯的“dumb pipe”。基於這些風格,在微服務架構中不可避免的出現了幾種通訊模式。

點到點風格 – 直接呼叫服務

以點對點的形式,訊息路由邏輯的整體跑在每個端點之上,服務可以直接通訊。這裡每個微伺服器都暴露一個REST API,一個給定的微伺服器或外部客戶端可以通過對應的REST API呼叫另一個微伺服器。

REST API

顯然,這個模型適用於相對簡單的基於微服務的應用。隨著服務數量增加,複雜就會壓倒一切的源頭。傳統SOA實現中使用ESB也是相同的原因,不過是為了擺脫混亂的點對點整合連結。總結微服務通訊中點對點風格的缺點:

  1. 須在每個微服務級別實現終端使用者認證,限制,監控等非功能性要求。
  2. 由於不可避免的複製一些常用功能,每個微服務實現可能會變得複雜。
  3. 服務和客戶端之間的所有通訊都無法控制(哪怕只是監控,跟蹤或過濾)。
  4. 通常直接溝通風格被認為是用於大規模微服務實現的微服務反向模式。

特徵說完,總結:對於複雜的微服務用例,可以考慮輕量級的中央訊息匯流排,而不是點對點連線或中心ESB,思路是為微服務提供一個抽象層,並可用於實現各種非功能的能力,這種風格被稱為API閘道器風格,往下看。

API閘道器樣式

API閘道器風格背後的關鍵思想是使用輕量級訊息閘道器作為所有客戶端/消費者的主要入口點,並在Gateway級別實現常見的非功能需求。通常,API閘道器允許通過REST/HTTP使用受管API。

因此,在這裡,我們可以將通過API-GW實現作為微服務的業務功能公開為管理API。Microservices架構和API管理的組合,這個算是最佳選擇了。

API

在我們的零售業務場景中,如圖5,所有的微服務都通過API-GW公開,這是所有客戶端的單個入口點。總結下API-GW風格優勢:

  • 能夠在現有微服務的閘道器級別提供所需的抽象。例如,API閘道器可以為每個客戶端提供不同的API,而不是提一個所有型別的API。
  • 閘道器級、輕量級訊息路由/轉換。
  • 非功能性功能(如安全性,監控和調節)的應用能如臂指使。
  • API-GW模式讓非功能性要求在Gateway級別實現,微服務得以瘦身。

比較推薦API-GW,我沒具體瞭解過,但這個應該也是應用最廣泛的模式。

Message Broker風格

微服務還可以和非同步訊息的場景整合,比如佇列或主題的單向請求以及訂閱。給定的微服務可以做訊息生成,並且它可以非同步地將訊息傳送到佇列或主題。那麼消費的微伺服器可以消耗來自佇列或主題的訊息。這種風格將訊息生成與訊息消費分離,中間訊息代理緩衝直到消費處理。

微服務

消費/生產之間的通訊基於非同步訊息標準(例如AMQP,MQTT等)的訊息代理來實現。

分散式資料管理

單片架構中,應用將資料儲存在單個和集中的資料庫中,以實現應用的各種功能/功能。

資料

在微服務體系結構中,功能分散在多個微伺服器中,如果我們使用相同的集中式資料庫,那麼微伺服器將不再彼此獨立(例如,如果資料庫模式已經從給定的微伺服器發生變化)。因此,每個微伺服器都必須擁有自己的資料庫。

微伺服器

以下是在微服務架構中實施分散資料管理的關鍵方面:

  • 每個微伺服器都可以有一個私有資料庫來儲存實現從其提供的業務功能所需的資料。
  • 給定的微伺服器只能訪問專用私有資料庫,而不能訪問其他微伺服器的資料庫。
  • 某些業務場景中,可能單個事務需要更新多個數據庫。在這種情況,其他微伺服器的資料庫應僅通過其服務API進行更新,而非直接訪問。

非集中式資料管理提供完全解耦的微伺服器,以及選擇不同資料管理技術(SQL或NoSQL等,按需分配,可能不同資料庫管理系統)的自由。再者對於涉及多個微服務的複雜事務用例,事務行為必須使用從每個服務提供的API來實現,並且邏輯位於客戶端或中間(GW)級別。

權力下放的治理思維

微服務架構傾向於分散治理。一般來說,SOA治理指導了可重用服務的開發,建立如何設計和開發服務以及這些服務隨時間的變化。它確定了服務提供商和這些服務的消費者之間的協議,告訴消費者他們期望什麼以及提供者有義務提供什麼。在SOA治理中,共有兩種型別的治理:

  • 設計時治理 – 定義和控制服務策略的服務建立,設計和實施;
  • 執行時管理 – 執行期間執行服務策略的能力;

那麼,微服務環境中的治理究竟怎麼理解?在微服務架構中,微服務通過各種技術和平臺構建為完全獨立和解耦服務。因此,不需要為服務設計和開發定義一個共同的標準。總結下微服務的權力下放治理能力:

  • 在微服務架構中,管理不需要集中設計。
  • 微伺服器可以因地制宜,決定其設計和實現。
  • 微服務架構促進了共享/可重用服務的共享。
  • 一些執行時管理方面,如SLA,節流,監控,常見安全要求和服務發現可以在API-GW級別實現。

服務註冊和服務發現

在微服務架構中,需要處理的微伺服器數量相當高。而且,由於微服務的快速和敏捷的開發/部署性質,他們的位置一般來說也會動態變化。因此,你需要在執行時間內找到微伺服器的位置。解決此問題的方法是使用Service Registry。

服務登錄檔

服務登錄檔儲存微服務例項及其位置。Microservice例項在啟動時註冊到服務登錄檔,並在關機時登出。消費者可以通過服務登錄檔找到可用的微服務及其位置。

服務發現

要找到可用的微服務及其位置,我們要一個服務發現機制。有兩種型別的服務發現機制,客戶端發現和伺服器端發現,來看看這些服務發現機制各原理如何。

客戶端發現: 

在這種方法中,客戶端或API-GW通過查詢服務登錄檔來獲取服務例項的位置。

這裡客戶端/API-GW必須通過呼叫Service-Registry元件來實現服務發現邏輯。

伺服器端發現:

通過這種方法,客戶機/API-GW將請求傳送到在眾所周知的位置執行的元件(如負載平衡器)。該元件呼叫服務登錄檔並確定微伺服器的絕對位置。

Kubernetes等微服務部署解決方案提供了服務端發現機制,自媒體裡連結不能發就算了。

部署

在微服務架構方面,微服務的部署同樣起著至關重要的作用,關鍵要求如下:

  • 能夠獨立於其他微服務部署/部署。
  • 必須能在每個微服務級別做擴充套件(給定的服務可能比其他服務獲得更多的流量)。
  • 快速構建和部署。
  • 一個微服務的故障不得影響任何其他服務。

Docker提供了一種很好的方式來部署滿足上述要求的微伺服器,所涉及的關鍵步驟如下:

  • 將微服務作為(Docker)容器映象打包。
  • 將每個服務例項部署為容器。
  • 基於更改容器例項的數量來進行縮放。
  • 構建,部署和啟動微服務將會快得多,因為我們使用Docker容器(這比常規VM快得多)

Kubernetes通過允許將一組Linux容器作為單個系統進行管理,在多個主機上管理和執行Docker容器,提供容器的共同位置,服務發現和複製控制,從而擴充套件Docker功能。其實大多數這些功能在微服務環境中也很重要,因此使用Kubernetes(在Docker上面)用於微服務部署已經成為一種非常強大的方法,特別是對於大規模微服務部署。

微服務部署

圖11,顯示了零售應用的微服務部署概述。每個微服務例項被部署為容器,每個主機有兩個容器。同時可隨意更改在給定主機上執行的容器數。

 

安全

現實很骨感,無論是不是微服務都應當得到安全方面的保護。在進入微服務安全性篇章之前,我們先快速過一下如何在單片應用層面實現安全。

  • 在典型的單片應用程式中,安全性是關於發現“誰是呼叫者”,“呼叫者可以做什麼”,以及“我們如何傳播該資訊”。
  • 這通常在位於請求處理鏈的開始處的公共安全元件中實現,該元件使用底層使用者儲存庫(或使用者儲存)填充所需的資訊。

那麼,我們可以直接將這種模式轉化為微服務架構嗎?是的,但是這需要在每個微服務級別實現安全元件,該級別正在與集中式/共享使用者儲存庫進行通訊,並檢索所需的資訊。這是解決Microservices安全問題的一種非常乏味的方法。

還有,劃重點,我們可以利用廣泛使用的API-Security標準(如OAuth2和OpenID Connect)來找到我們的Microservices安全問題的更好的解決方案。在深入瞭解之前,我來總結下這些標準。

  • OAuth2 – 是訪問委派協議。客戶端使用授權伺服器進行身份驗證,並獲取稱為“訪問令牌”的不透明令牌。Access令牌具有關於使用者/客戶端的零資訊。它僅引用只能由授權伺服器檢索的使用者資訊。因此,這被稱為“副參考令牌”,即使在公共網路/網際網路中也可以安全地使用該令牌。
  • OpenID Connect的行為與OAuth類似,但是除了訪問令牌之外,授權伺服器還會發出一個包含使用者資訊的ID令牌。這通常由JWT(JSON Web令牌)實現,並由授權伺服器簽名。因此,可以確保授權伺服器與客戶端之間的信任。因此,JWT令牌被稱為“副值令牌”,因為它包含使用者的資訊,顯然不能在內部網路之外使用它。

現在,讓我們看看我們如何使用這些標準來保護我們零售業的微觀服務。

微觀服務

如圖12,這些是實現微服務安全性的關鍵步驟:

  • 將身份驗證保留到OAuth和OpenID Connect伺服器(授權伺服器),以便microservices成功提供訪問許可權,因為有人有權使用資料。
  • 使用API-GW樣式,其中所有客戶端請求都有一個入口。
  • 客戶端連線到授權伺服器並獲取訪問令牌(按引用令牌)。然後將訪問令牌與請求一起傳送到API-GW。
  • 閘道器上的令牌翻譯:API-GW提取訪問令牌,並將其傳送到授權伺服器以通過值令牌來檢索JWT。
  • GW將該JWT與請求一起傳遞到微服務層。
  • JWT包含有助於儲存使用者會話等的必要資訊。如果每個服務都可以瞭解JSON – Web令牌,那麼已經分發了你的身份機制,那你就被允許在整個系統中傳輸身份。
  • 在每個微服務層,我們可以有一個處理JWT的元件,這是一個非常簡單的實現。

交易

微服務中的交易支援如何?其實,支援跨多個微服務的分散式事務是一個非常複雜的任務。

微服務架構本身鼓勵服務之間的無事務協調。這個想法是給定的服務是完全獨立,基於單一的責任原則。跨多個微伺服器分散式事務的需要通常是微服務體系結構設計缺陷的症狀,通常可以通過重構微伺服器的範圍進行整理。

然而,如果強制性要求跨多個服務進行分散式交易,則可以通過在每個微服務級別引入“補償操作”來實現這種情況。關鍵思想是,給定的微服務是基於單一責任原則,如果給定的微伺服器未能執行給定的操作,那麼我們可以認為這是整個微服務的失敗。

設計失敗

Microservice架構引入了一系列分散的服務,與單片設計相比,增加了在每個服務級別發生故障的可能性。由於網路問題,基礎資源不可用,給定的微服務可能會失敗。不可用或無響應的微伺服器不應玩砸了整個基於微伺服器的應用。因此,微服務應該有容錯餘地,能夠在可能的情況下恢復,客戶端也必須妥善處理。

此外,由於服務可能隨時失敗,因此能夠快速檢測(實時監控)故障,並儘可能自動恢復服務(故障自愈)很重要。

在微服務玩家的眼裡,處理錯誤有幾種常用模式。

斷路器 

當你對微伺服器進行外部呼叫,就可以在每次呼叫時配置故障監視器元件,並且當故障達到某個閾值時該元件將停止對服務的任何進一步呼叫(跳閘電路)。在開啟狀態(可以配置)的一定數量的請求後,將電路更換回關閉狀態。
這種模式對於避免不必要的資源消耗,由於超時引起的請求延遲是非常有用,也讓我們有機會更積極的監控系統(基於活動的開路狀態)。

隔板 

基於微伺服器的應用的一部分的故障不應影響其他應用,隔板模式是關於隔離應用的不同部分,以便應用的某個部分的服務失敗不會影響任何其他服務。

超時 

超時是一種主觀加入的合理機制,當你認為結果無法返回,則允許停止響應。

模式這裡叨叨完。那麼,我們在哪裡和如何使用這些模式與微服務?大多數情況下這些模式都適用於Gateway級別,這意味著當微服務不可用或沒有響應時,在閘道器級別,我們可以決定是否使用斷路器或超時模式將請求傳送到微服務。此外,在Gateway級別實現諸如隔板之類模式也很重要,因為它是所有客戶端請求的單個入口點,也因此傳送服務中的故障不應影響其他微伺服器的呼叫。

另外,Gateway可以作為中心點,我們可以通過Gateway呼叫每個微服務來獲取每個微伺服器的狀態和監視。

微服務,企業整合,API管理和遐(瞎)想

們專門研究過微服務架構的各種特點,以及如何在現代企業IT環境中實現它們。但是,我們應該記住,微服務不是靈丹妙藥。流行語概念的盲目適應不會解決“真實”企業IT問題。

它微服務是有很多優勢,我們也應該充分利用。但是我們還必須記住,解決所有企業IT問題與微服務之間聯絡不一定就是強相關。例如,Microservices架構促進消除ESB作為中央匯流排,但是當涉及到現實世界的IT時,現在有很多不是基於Microservices的應用程式/服務。所以,整合是避不開的解決思路,要做整合。

所以,理想情況下,Microservices和其他企業架構概念(如Integration)的混合方法將更為現實。以後再聊了,這個能寫的太多。 希望這能讓你更清楚地瞭解如何在企業中使用Microservices。