1. 程式人生 > 實用技巧 >微服務架構帶來的挑戰,以及微服務的9大特性!!!

微服務架構帶來的挑戰,以及微服務的9大特性!!!

微服務是近三年來較為熱門的話題,而我本人自去年接觸微服務開始,就對其產生了較為濃厚的興趣,公司也在嘗試將之前的單體架構向微服務架構過渡,因此打算系統的學習一下微服務相關的知識。主要學習微服務的思想,架構設計以及SpringCloud生態的各類元件,涵蓋了服務治理元件Eureka,客戶端負載均衡元件Ribbon,服務容錯保護元件Hystrix,宣告式服務呼叫元件Feign,API閘道器治理元件Zuul,分散式配置中心元件Config,訊息匯流排元件Bus,訊息驅動元件Stream,分散式跟蹤元件Sleuth等,這些幾乎囊括了開發者在實施微服務中需要深入瞭解的各種輪子,當然在學習這些元件的同時更要理解其中的底層實現原理。

基礎知識

在學習SpringCloud具體內容之前需要了解一些微服務架構以及SpringCloud的基礎知識,這些都是後續學習SpringCloud的基礎,同時這裡也會簡單介紹SpringCloud能解決的問題,帶著問題,有目的性的學習可以極大的提升學習效率。

微服務架構

微服務一詞來源於Martin Fowle寫的一篇文章,開發者可以點選 這裡,閱讀該文章詳情,閱讀中文翻譯請點選 這裡。

簡單來說,微服務是系統架構上的一種設計風格,它的主旨是將一個原本獨立的系統拆分成多個小型服務,這些小型服務都在各自獨立的程序中運 行,服務之間通過基於HTTP的RESTful風格的API進行通訊協作。注意被拆分的每一個小型服務都是圍繞著系統中某一項或者一些耦合度較高的業務功能進行構建,並且每個服務都維護著自身的資料儲存、業務開發、自動化測試案例以及獨立部署機制。由於存在輕量級的通訊協議作基礎,因此這些微服務可以使用不同的語言來不編寫。

與單體系統的區別

在以往傳統的企業系統架構中,我們針對一個複雜的業務需求通常使用物件或業務型別來構建一個單體專案。在專案中通常將需求分為三個主要部分:資料庫、服務端處理、前端展現。在業務發展初期,由於所有的業務邏輯在一個應用中,開發、測試、部署都還比較容易且方便。但是隨著企業的發展,系統為了應對不同的業務需求會不斷為該單體專案增加不同的業務模組;同時隨著移動裝置的進步,前端展現模組已經不僅僅侷限於Web的形式,這對於系統後端向前端的支援需要更多的介面模組。不斷擴大的需求使得單體應用變得越來越臃腫,因此單體應用的缺點也越來越明顯。由於單體系統部署在一個程序內,因此當我們修改了一個很小的功能,然後部署上線很可能會影響其他功能的執行。且單體應用中的各個模組的使用場景、併發量、消耗的資源型別等都是不同的,對於資源的利用又是互相影響,這樣無疑給我們對於各個業務模組的系統容量的評估帶來巨大的影響,這麼看來儘管單體系統在初期可以很方便的進行開發和使用,但是隨著系統的發展,毫無疑問其維護成本會變得越來越大,且非常難以控制。

為了解決單體系統變得臃腫後難以維護的問題,微服務架構孕育而生。我們可以將系統中不同的功能模組拆分成多個不同的服務,這些服務都能夠獨立部署和擴充套件。由於每個服務都執行在自己的程序內,在部署上有穩固的邊界,這樣每個服務的更新都不會影響到其他服務的執行。同時由於各個服務均是獨立部署的,因此可以更為準確的為每個服務進行效能容量評估,與此同時通過配合服務間的協作流程也可以更容易的發現系統的瓶頸位置,並給出較為準確的系統級效能容量評估。

微服務帶來的挑戰

在實施微服務之前,有必要知道因為微服務的拆分而引發了諸多原本在單體應用中沒有的問題和挑戰:

(1)運維的新高度。在微服務架構中,由於系統的拆分,使得運維人員需要維護的程序數量大大增加,這就要求運維人員具備一定的開發能力來編排運維過程並讓它們能自動執行起來。

(2)介面的一致性。雖然我們拆分了服務,但是業務邏輯上的依賴並不會消除,只是從單體應用中的程式碼依賴變為了微服務間的通訊依賴。這就使得開發者對原有介面進行了一絲修改,那麼與之對應的互動方也需要協調這樣的改變來進行釋出,以保證介面的正確呼叫。也就是說此時需要更完善的介面和版本管理,或者是嚴格遵循開閉原則。

(3)分散式的複雜性。由於拆分後的各個微服務都是獨立部署並執行在各自的程序內,它們只能通過通訊來進行協作,所以分散式環境的問題都是微服務架構設計時需要考慮的重要因素,如網路延遲、分散式事務、非同步訊息等。

儘管微服務架構中存在很多缺點,但是你知道的凡是都有兩面性,關鍵在於如何取捨,當你覺得微服務架構中實現的敏捷開發、自動化部署等是你著重需要考慮的問題,那麼此時選擇微服務架構是不錯的選擇。

微服務9大特性

由於存在環境、資源、團隊等各種因素的影響,因此架構師在對一個大型系統架構的設計與實施過程中幾乎不會出現完全相同的架構設計。對於微服務架構而言更是如此,由於微服務架構只是一種建議,不是硬性規定,因此架構師通常會根據自身理解和實際情況來進行設計,並在發展的過程中不斷演進和完善。當然了,俗話說的好,不以規矩無以成方圓,因此非服務架構存在9大特性,通過這9大特性的學習,對於架構師設計架構有著指導性意義。

(1)服務元件化。所謂的元件,是指一個可以獨立更換和升級的單元。在微服務架構中,需要我們對服務進行元件化分解。服務,是一種程序外的元件,它通過HTTP等通訊協議進行協作,而不是像傳統元件那樣以嵌入的方式協調工作。每一個服務都獨立開發、測試、部署,可以有效的避免一個服務的修改引起整個系統的重新部署。

(2)按業務組織團隊。當決定如何劃分微服務時,通常也意味著我們要開始對團隊進行重新規劃和組織。按照以往的方式,我們會從技術層面將團隊劃分為多個,如DBA團隊,運維團隊,後端團隊,前端團隊,設計師團隊等。但是如果我們此時還按照這種方式組織團隊來實施微服務架構開發,那麼極易出現當一個服務需要修改時(可能是一個非常簡單的變動,如對某個物件新增一個欄位等),那麼這就要求從資料儲存開始考慮一直到設計和前端,儘管大家修改的內容很少,甚至部分節點是不需要修改的,但是這勢必會造成不必要的跨團隊溝通,而這在企業中儘量是需要避免的。

在微服務架構的實施時,需要採用不同的團隊分割方法。由於每一個服務都是針對特定業務的寬棧或者是全棧實現,既要負責資料的持久化儲存,又要負責使用者的介面定義等各種跨專業領域職能。因此在面對大型專案的時候,對於微服務團隊的拆分筆者建議按照業務線的方式進行拆分,一方面可以有效的減少服務內部修改所產生的內耗;另一方面團隊的邊界變得更加清晰。

(3)做產品的態度。在實施微服務架構的團隊中,每個小團隊都應該是以做產品的方式對其產品的整個生命週期負責,而不是以專案的模式,以完成開發與互動並將成果交給維護者為最終目標。

一般來說,開發團隊通過了解服務在具體生產環境中的情況,可以增加他們對於具體業務的理解,所以需要開發者用做產品的態度來對待每一個微服務,持續關注服務的運作情況,並不斷分析以幫助使用者來改善業務功能。

(4)智慧端點與啞管道。在單體應用中,元件之間可以直接通過函式呼叫的方式來進行互動協作;而在微服務架構中,由於服務不在一個程序中,因此元件的通訊模式傳送了變化,如果僅僅是將原本在程序內的方法呼叫改成RPC方式的呼叫,這樣會導致微服務之間產生繁瑣的通訊,使得系統表現更為糟糕,因此我們需要更粗粒度的通訊協議。

在微服務架構中,一般會使用如下兩種服務呼叫方式:(1)使用HTTP的RESTful風格的API或者輕量級的訊息傳送協議,實現訊息傳遞與服務呼叫的觸發。(2)通過在輕量級的訊息總線上傳遞訊息,使用類似於RabbitMQ等一些提供可靠非同步交換的中介軟體。

除了上述兩種方式之外,在一些極度強調效能的情況下,有些團隊會使用二進位制的訊息傳送協議,如protobuf。但是即便是這樣,這些系統依舊可能出現前面說的“智慧端點與啞管道”的特點,這是為了在易讀性和高效性之間取得平衡。當然了,大多數的Web應用或者企業系統其實並不需要在這兩者之間做出選擇,因為能夠獲得易讀性已經是非常不錯了。

(5)去中心化治理。當我們採用集中化的架構治理方案時,通常在技術平臺上都會制定統一的標準,但是每一種技術都有它合適的應用場景,並不是適合所有的場景,這樣在碰到其短板時,就需要花費大力氣去解決,而且極有可能在日後成為系統的瓶頸。

在實施微服務架構時,通過採用輕量級的契約定義介面,使得我們對於服務本身的技術平臺不再那麼敏感,這樣整個微服務架構系統中的各個元件就能針對其不同的業務特點選擇不同的技術平臺,使用最合適的技術,這樣就不會出現殺雞焉用牛刀的尷尬局面。

我非常喜歡一句話:不是每個問題都是釘子,也不是每個解決方案都是錘子。

(6)去中心化管理資料。我們在實施微服務架構時,都希望讓每一個服務來管理其自有的資料庫,這其實就是資料管理的去中心化。

在去中心化過程中,我們除了將原資料庫中的儲存內容拆分到新的的同平臺的其他資料庫例項之中(如將原本儲存在MySQL中的表拆分後,儲存到多個不同的MySQL例項中),當然也可以將一些具有特殊結構或者業務特性的資料儲存到一些其他技術的資料庫例項中,如將日誌資訊儲存到MongoDB或者將使用者資訊儲存到Redis中。

雖然資料管理的去中心化可以讓資料管理變得更加細緻化,之後通過採用更合適的技術可以讓資料儲存和效能達到最優解。但是由於資料儲存於不同的資料庫例項中,那麼資料一致性也就成了微服務架構中亟待解決的問題,而分散式事務本身實現的難度就非常大,因此在微服務架構中我們更強調在各服務之間進行“無事務”的呼叫,而對於資料一致性,只要求資料在最後處理的狀態是一致的即可。如果在過程中發現錯誤,可以通過補償機制來進行處理,這樣使得錯誤資料能夠達到最終的一致性。

(7)基礎設施自動化。隨著雲端計算服務與容器技術的不斷髮展,運維基礎設施的工作變得越來越容易,但是當我們在實施微服務架構的時候,資料庫、應用程式雖然變都小了,但是因為拆分的原因,數量成倍增長,這也就使得運維人員不得不花費更多的時間去關注,且操作性任務也會成倍增長,如果這些問題一開始沒有引起足夠的重視,那麼勢必會加重運維人員的工作負擔。

因此,在微服務架構中必須從一開始就構建起“持續交付”平臺來支撐整個實施過程,一般來說都會包含兩個部分:自動化測試和自動化部署。

(8)容錯設計。在單體應用中,一般不存在單個元件故障而其他元件還在執行的情況,通常都是一掛而全掛。但是在微服務架構中,由於各個服務都是執行在獨立的程序中,所以存在部分服務出現故障,而其他服務還正常執行的情況。舉個例子,假設執行正常的服務B呼叫發生故障的服務A時,由於故障服務A沒有返回,執行緒被掛起等待,直到超時才會被釋放,而此時若觸發服務B呼叫服務A的請求來自於服務C,而服務C頻繁呼叫服務B時,由於其依賴服務A,大量執行緒被掛起等待,最後導致服務A也不能正常服務,此時就會出現故障的蔓延。

鑑於此種情形,在微服務架構中快速檢測出故障來源並儘可能的自動恢復服務是必須被設計和考慮的。一般來說,我們都希望在每個服務中實現監控和日誌記錄的元件,然後提供諸如服務狀態、斷路器狀態、吞吐量、網路延遲等關鍵資料的儀表盤等。

(9)演進式設計。其實通過上面的學習,我們可以發現要實施一個完美的微服務架構,需要考慮很多東西且成本也挺大的,對於一些沒有過足夠經驗的團隊來說,極易可能付出比單體架構應用更多的代價。

因此在很多情況下,架構師都會以演進的方式進行系統的構建,也就是說一個好的架構不是設計出來的,而是演進出來的。在初期,一般會以單體架構來設計和實施,一方面是因為系統初期體量不會太大,構建和維護成本都不高;另一方面初期的核心業務在後期通常也不會發生巨大的變化。隨著系統的發展或者業務的需要,架構師會將一些經常變動或者是有一段時間效應的內容進行微服務處理,並逐漸將原來在單體系統中多變的模組拆分出來,而穩定不太變化的模組就形成了一個核心微服務存在於整個架構中。

微服務技術

接下來學習一些優秀企業分享的它們在微服務架構中針對不同應用場景出現的各種問題的各種解決方案和開源框架:

(1)服務治理:阿里巴巴開源的Dubbo和噹噹網在其基礎上擴充套件的DubboX、NetFlix的Eureka、Apache的Consul等;

(2)分散式配置管理:百度的Disconf、Netflix的Archaius、360的QConf、Spring Cloud的Config、淘寶的Diamond等;

(3)批量任務:噹噹網的Elastic-Job、LinkedIn的Azkaban、Spring Cloud的Task等;

(4)服務跟蹤:京東的Hydra、Spring Cloud Sleuth和Twitter的Zipkin等;

當然上面列舉的只是一部分,對於有選擇困難症的人來說,對於某一個問題存在多個答案的選擇也是一個問題。其實仔細看也就發現上面這些框架都是為了解決部分問題,那麼問題來了其實完全可以選擇一個較為系統的工具,Spring Cloud就是這樣的工具,它是一個解決微服務架構實施的綜合性解決框架,它不是重複的造輪子,而是整合諸多被廣泛實踐和證明過的框架作為實施的基礎部件,然後在該基礎上建立了一些非常優秀的邊緣元件。

Spring Cloud簡介

Spring Cloud是一個基於Spring Boot實現的微服務架構開發工具,它為微服務架構中涉及的配置管理、服務治理、斷路器、智慧路由、微代理、控制匯流排、全域性鎖、決策競選、分散式會話和叢集狀態管理等操作提供了一種簡單的開發方式。

Spring Cloud包含了很多子專案,如下所示:

(1)Spring Cloud Config:配置管理,支援使用Git儲存配置內容,可以使用它來實現應用配置的外部化儲存,並支援客戶端配置資訊重新整理、加密/解密配置內容等;

(2)Spring Cloud Netflix:這是Spring Cloud的核心元件,對多個Netflix OSS開源套件進行整合:

  • Eureka:服務治理元件,包含服務註冊中心、服務註冊與服務發現機制的實現;

  • Hystrix:容錯管理元件,實現斷路器模式,幫助服務依賴中出現的延遲和為故障提供強大的容錯能力;

  • Ribbon:客戶端負載均衡的服務呼叫元件;

  • Feign:基於Ribbon和Hystrix的宣告式服務呼叫元件;

  • Zuul:閘道器元件,提供智慧路由、訪問過濾等功能;

  • Archaius:外部化配置元件。

(3)Spring Cloud Bus:事件、訊息匯流排,用於傳播叢集中的狀態變化或事件,以觸發後續的處理,如用來動態重新整理配置資訊等;

(4)Spring Cloud Cluster:針對Zookeeper、Redis、Hazelcast、Consul的選舉演算法和通用模式的實現;

(5)Spring Cloud Cloudfoundry:與Pivotal Cloudfoundry的整合支援;(6)Spring Cloud Consul:服務發現與配置管理工具;

(7)Spring Cloud Stream:通過Redis、RabbitMQ或者Kafka實現的消費微服務,可以通過簡單的宣告式模型來發送和接收訊息;

(8)Spring Cloud AWS:用於簡化整合Amazon Web Service的元件;

(9)Spring Cloud Security:安全工具包,提供在Zuul代理中對於OAuth2客戶端請求的中繼器;

(10)Spring Cloud Sleuth:Spring Cloud應用的分散式服務跟蹤實現,可以完美的整合Zipkin;

(11)Spring Cloud Zookeeper:基於Zookeeper的服務發現與配置管理元件;

(12)Spring Cloud Starters:Spring Cloud的基礎元件,它是基於Spring Boot風格專案的基礎依賴模組;

(13)Spring Cloud CLI:用於在Groovy中快速建立Spring Cloud應用的Spring Boot CLI外掛。

當然絕對不只是這些元件,還有很多的元件等著我們去學習。

版本說明

請注意Spring Cloud它只是一個工具集的名稱,而不像Spring社群其他一些專案那樣獨立,它是一個擁有諸多子專案的大型綜合專案,是對微服務架構解決方案的綜合套件組合,其包含的各個子專案也都獨立進行內容迭代和版本更新,各自都有自己的版本號。因此每一個Spring Cloud的版本中都會包含多個不同版本的子專案,為了管理每個版本的子專案清單,避免Spring Cloud的版本號與其子專案的版本號產生衝突,就沒有采用版本號的方式,而是通過命名的方式進行,更準確的說是採用倫敦地鐵站的名字,並根據字母表的順序來對應版本時間順序,如Angel、Brixton等,而之後跟的諸如SR5、SR6、SR7等則是版本號。舉個例子,本套學習筆記使用的是Hoxton.SR7版本,SR是service release版本,簡稱SRX,其中的X是遞增的數字,因此Hoxton.SR7就是Hoxton的第7個Release版本。