阿里P8 談微服務的應用架構設計

首先咱們經過一個最簡單的例子來看下如何構建一個微服務應用。git

圖 1 是一個完整服務的代碼,它和普通的應用程序沒什麼區別,只是功能很是少,業務很是簡單。把它編譯以後部署在服務端就能跑起來,咱們從上往下解釋一下這段代碼幹了什麼事情:github

  1. 在第 6 行咱們引入一個包 「github.com/koding/kite」,這是一個開源的微服務框架包,使用它能夠快速方便的構建一個微服務應用;數據庫

  2. 第 11 和 12 行咱們定義一個微服務,並將其取名爲 first;後端

  3. 第 15 行開始咱們爲這個微服務添加了一個 square 操做指令供外部調用,這是負責完成具體功能的業務單元,在這裏它負責將外部傳入過來的值進行求平方計算後返回給調用方;設計模式

  4. 最後在第 21 行咱們把它註冊到框架提供的某個地方,並聲明瞭它的訪問地址和協議。緩存

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 1. 服務端代碼網絡

這個服務實現了一個供外部調用的功能,咱們把它稱之爲 server 端。接下來咱們再實現一個調用這個它的客戶端,咱們稱之爲 client 端。在真實的微服務環境中,並無嚴格區分 server 端和 client 端,只要有須要,它們均可能會相互調用。架構

一樣的,咱們從上往下看看圖 2 這段代碼幹了什麼事情:負載均衡

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 2. 客戶端的代碼框架

  1. 除了第 6 行引入的 「github.com/koding/kite」 包以外,咱們還引入了另一個 「github.com/koding/kite/protocol」 包,它用於作環境中的微服務發現;

  2. 第 15 行開始咱們經過配置環境中的信息在環境中查找全部名字爲 「first」 的微服務。之因此說「查找全部」,是由於在更復雜的生產環境中,一個微服務每每可能包含多個副本,而且這個副本數是動態伸縮的,所以須要專門的服務註冊和發現過程來動態註冊和動態查找,咱們後面會講到更具體的模式;

  3. 在第 22 行中咱們選擇第 1 個結果,也就是第一個微服務進行訪問;

  4. 在第 26 行中傳入參數 4,調用指令 「square」 求平方,獲得結果;


這是一個服務調用另外一個服務的演示過程,從中能夠看出它涉及到服務的構建、註冊和發現。後面這個 client 端例子在演示中雖然沒有監聽端口,只是訪問別的微服務,可是它也能監聽端口對外提供服務,本質上 server 和 client 兩端從微服務架構角度說並無嚴格區分,只是在不一樣時候扮演不一樣的角色履行不一樣的職責。

上面兩個示例中咱們提到服務註冊和發現。實際生產環境中,微服務的種類和每一個微服務副本數可能都很是多,特別是在相互調用以後,它們雜糅在一塊兒的業務可能很是複雜。同時,複雜多變的環境決定了系統中運行的微服務隨時可能被啓停,這也是擁抱微服務的價值點之一:主動擁抱系統的不穩定性,經過消除這種不穩定性帶來的影響來達到高可用的目的。爲此,須要引入服務註冊和發現機制來幫助系統治理這些服務。

服務註冊與發現

咱們再來看一下,爲何這麼簡單的代碼中還須要多一個服務註冊的步驟?

一個微服務起來以後,要對外提供服務,必須讓別人知道它的存在,所以須要有一個地方讓它「註冊」,咱們把它稱爲「註冊中心」。因爲微服務的啓停是隨時均可能發生的,和啓停對應的是服務的註冊和解除註冊,所以在這裏咱們說到註冊的時候默認也隱含解除註冊,後續再也不贅述。解除註冊是爲了保證下線的服務不會被調用方訪問到。

假如這兩個服務都有多個實例副本,它部署起來如圖 3 所示。在實際生產環境中,每一個服務實例 A、B 和 C 都是動態變化的,整個服務的過程當中可能一直有多個副本在那裏跑着,但不必定都是相同的實例,它們的 IP 在服務動態伸縮過程當中會發生變化。那麼如何讓客戶端及時的知道這種變化呢?咱們知道,微服務提倡多個服務解耦比較乾淨,所以讓一個服務主動通知另一個服務它的變化是不太現實的,這樣侵入對方業務太深了,耦合太緊。同時,在後端有多個服務實例的狀況下,如何將客戶端的請求負載均衡的分發到各個實例中呢?

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 3. 沒有服務發現的問題

在這些問題面前,和傳統的單體架構相比,微服務中服務的註冊和發現能力很是重要,甚至有些微服務框架自帶了服務的註冊和發現功能(好比咱們給的例子中用到的 kite 這個框架就自帶了這樣的功能)。

一個服務起來以後,它的註冊和解除註冊過程能夠由本身去完成,也能夠由第三方工具去完成。好比在客戶端和微服務端之間的負載均衡器可能會幫助微服務完成服務的註冊和解除註冊等操做,客戶端和微服務自身都不須要關心,也即不須要他們各自的業務邏輯裏面實現這些操做。還有一些狀況是在客戶端自帶服務查詢模塊,它先從服務註冊中心查詢可用的服務,而後再按照這個查詢結果去請求後端服務實例。下面咱們分別解釋這兩種模式。

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 3. 沒有服務發現的問題

圖 4 中給出的是以客戶端查詢爲主的服務註冊和發現機制,後端服務實例起來以後,會以主動或者被動的形式註冊到「註冊中心」。客戶端自帶的「查詢模塊」會從「註冊中心」查詢可用的服務,而後按照查詢結果去請求後端服務實例。

這樣作的好處是:

  • 「註冊中心」在服務以外維護,使用簡單,對已有的微服務架構侵入小;

  • 客戶端直接請求後端實例,查詢完成後請求鏈路不須要通過其它中間環節。

其缺點在於:

  • 客戶端和「註冊中心」綁定;

  • 客戶端的實現取決於具體語言或者框架,每一個客戶端都得本身去實現。

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 5. 服務端服務發現

咱們再來看下服務端實現的服務註冊和發現機制,如圖 5 所示。一樣的,後端服務實例起來以後,會經過主動或者被動的方式註冊到「註冊中心」,可是客戶端不須要實現查詢模塊去查詢服務了,取而代之的是咱們在服務端添加一個「路由」環節,它負責代理客戶端的全部請求,從後端實例獲取結果以後返回給客戶端。與客戶端服務發現機制相比,它具備如下優勢:

  • 客戶端不須要作額外的變動;

  • 有些雲服務公司已經提供相似產品能夠知足需求了,能夠直接接入。

  • 但它也有它的缺點:

  • 除非是託管在雲服務提供商那裏,不然還須要額外的服務端來部署「路由」或者「負載均衡器」部分,這也就意味着須要保證這個部分的可靠性和可用性,須要額外的系統設計和運維工做;

  • 請求多了一個路由代理的步驟,增長系統整體耗時。

在這裏給你們提供一個交流,討論的平臺,JAVA微服務討論羣:671017482 ,

微服務測試

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 6. 測試金字塔

咱們今天介紹微服務,首先假設系統到了必定的複雜度,使用傳統的單體架構已經不能知足需求了,必須將單體架構上的功能拆分紅職責和功能單一的微服務才能更好的跟上業務的發展。所以,由微服務構建的系統每每是一個複雜的分佈式系統,它的測試涉及到從裏到外的各個環節。

接下來咱們分三部分來介紹分佈式系統中涉及到的測試:常規測試、混沌測試和流量重現。

咱們先來看一個測試金字塔,如圖 6 所示,它包含:單元測試、集成測試、組件測試、端到端測試和探索性測試。接下來咱們要介紹的「常規測試」包含金字塔地下的四部分,它還包含另一種不太常見類型的測試,也即契約測試,下面會介紹到。而混沌測試或者猴子測試則屬於探索性測試。

常規測試

1. 單元測試

單元測試是幾乎全部系統開發都會涉及到的環節,它覆蓋最細粒度的測試範圍,通常基於類甚至是方法來進行自動化測試。它測試的範疇通常不涉及跨網絡的調用,所以相對簡單。在傳統的 Web 開發中,很是流行的測試驅動開發 TDD 裏面講的測試通常基於單元測試,單元測試用例不只定義了業務邊界,還將業務模塊進行了細分。

2. 集成測試

集成測試將相關模塊組合在一塊兒,在業務上構成一個子系統進行測試,它的主要目的在於驗證構成一個子系統的全部路勁上的調用是否正確,模塊組合在一塊兒後調用產生的結果是否符合預期。好比兩個服務之間的調用,或者服務和數據庫之間的通訊,通常都屬於集成測試的範疇。

3. 組件測試

與集成測試相反,組件測試關注的是組件內部功能的完備性。對於微服務應用來講,一個微服務即一個組件,爲了測試這個組件內部功能的完備性,須要儘可能減小外部環境對其形成的影響。當該微服務依賴於一些外部服務或者數據庫調用的時候,咱們能夠 mock 一些外部服務,同時使用內存數據來代替數據庫數據,這樣能夠儘可能減小外部服務調用對它產生的影響,只關注單個微服務自身的測試。

4. 契約測試

契約測試和組件測試的所需的邊界很是像,對於微服務來講,它們的所涉及的邊界都是微服務自己。但和組件測試不一樣的是,契約測試更關注輸入參數和輸出結果的合法性,必定的合法輸入必須獲得必定的合法輸出,也即測試一個服務是否知足必定的契約;另外,契約測試還關注相應的結果是在多長時間內獲得的,也即服務響應的性能。這時候對一個服務的測試,其所依賴的服務不能經過 mock 或者內存數據來代替。

5. 端到端測試

爲了驗證一個系統是否符合客戶需求和商業目標,須要一個覆蓋產品完整鏈路的測試。對於有用戶 UI 界面的產品,端到端的測試意味着包括 UI 界面的測試和後端服務的測試。因爲涉及到的環節最多,所以這樣的測試運行起來也比較慢,出現故障的時候排查問題也比較麻煩。爲了加快這個測試環節,一般建議:

  1. 將盡量多的測試需求自動化。

  2. 沒必要每一個組件的修改都觸發端到端測試,能夠在全部更小粒度的測試完成以後再作一遍端到端測試。

之因此把上面全部的測試稱爲「常規測試」,是由於這些測試基本上在全部類型的現代化軟件開發中均可能涉及到,它其實不是微服務架構都有的,微服務架構下的這些測試只是邊界不太同樣。統計對比代表,上線以前完整的測試能夠避免 90% 以上的錯誤致使的故障。

關於常規的測試,咱們只在這裏作簡單的介紹


混沌測試

在分佈式系統領域,Netflix 發明了一種更爲古怪的測試,叫混沌測試,Netflix 稱之爲猴子測試。什麼意思呢?它假設,若是你的系統足夠健壯,那麼隨便啓停某些服務並不會影響系統的總體運行,用戶並不會感知到服務的故障。咱們常常講要構建容忍故障的高可用服務,可是若是故障沒有來,就無法驗證這樣的服務是否能夠容忍某些極端狀況的故障。爲此,Netflix 在系統中引入了一系列搞破壞的「猴子」,它會主動給系統的各個部分製造麻煩,好比隨時不當心關閉一臺機器,可是你的服務還得繼續運行,全部故障必須自動恢復,而且不能被用戶感知到。

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 7. Netflix猴子軍團

Netflix 的猴子軍團:

  • Chaos Monkey: 隨機殺死實例

  • Latency Monkey: 人爲引入延遲

  • Chaos Gorilla: 模擬整個可用區忽然斷電

猴子軍團中的幾種不一樣類型的機器人分別表明了不一樣的破壞性,它在穩定的線上環境中隨機選擇破壞。這樣的測試模擬了天然災難,對線上環境進行了全黑盒式的演練,讓線上系統產生「免疫」。遺憾的是,即使所幸躲過全部這些「天然災難」,也沒法說明系統是沒問題的。


流量重現

咱們前面提到端到端的測試很難作,主要是難在它整個鏈路太長,耗時太長,環節也難以控制。另一個難點在於,咱們一般很難得到和線上同樣真實的流量去進行端到端的測試,即使某個環節可以成功模擬相應的請求,但也不是全部請求的比例和線上都是一致的。

爲了模擬線上請求,咱們能夠講線上流量截獲後導入到測試環境中經過「流量重現」的方式,在一個更加真實的模擬環境中觀察和調整。在這裏介紹一個用 Go 寫的開源工具:Gor https://github.com/buger/gor

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 8. 流量重現工具 Gor

經過監聽線上服務的請求,它可以截獲線上環境的流量,並將其在測試和開發環境中重現,如上圖所示。

典型微服務架構設計模式

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 9. 典型微服務設計模式

圖 9 是一個典型的微服務架構圖。服務註冊和發現的架構圖前面講過,爲了簡化圖的結構,此圖再也不說起。客戶端的請求首先會到達一個負責對外溝通的 API Gateway,它負責識別客戶端類型,解析和理解客戶端的請求,並將請求分發到後端對應的微服務中完成。

通常來說,基於 HTTP REST API 的請求都是同步執行的,可是有些場景使用異步的方式更爲合理,好比大視頻轉碼服務,它很難在很短期內完成。同時,爲了最大化微服務之間的解耦,應儘可能減小和簡化微服務之間的通訊。爲此,咱們引入消息隊列做爲異步通訊的通道。

在微服務的後端,若是每一個微服務都按照三層結構來部署,除了服務自己以外,還包括緩存層和持久化的數據庫層。

這樣就構成了一個典型的微服務應用架構,各項服務能夠自由伸縮,相互之間依賴最小化,經過共享隊列的方式來進行數據共享和信息同步。固然,這樣一個架構要經過猴子軍團的測試,首先得保證每一個組件都是高可用甚至是跨機房部署的,好比 API Gateway、消息隊列以及每一個服務依賴的 Cache 和 DB 都隨時可能掛掉。

七牛的微服務架構實踐

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

圖 10. 七牛微服務設計實踐

圖 10 展現的是七牛數據處理平臺的微服務架構示意圖。七牛的數據處理平臺天天處理接近百億的數據處理請求,這些請求包括圖片縮放裁剪等能夠實時完成的同步請求,也包括音視頻轉碼等沒法實時完成的異步請求。全部這些請求經過統一的網關進入負載均衡器,再由負載均衡器分發給後端的處理實例。後端的處理實例中,每一個實例只部署一種類型的服務,同時維持一個 Agent 能夠從存儲中讀取數據,以及一個 Cache 用於維持狀態。因爲業務相對簡單,Cache 能夠直接基於內存,而且沒有持久化的要求。全部持久化的工做都由客戶端主動發起,由後端 Agent 完成後對存儲進行讀寫。

問答環節

  • :關於微服務的註冊和發現,目前有哪些成熟的產品?

  • :比較成熟的用於協同的是 Zookeeper,在開源容器產品裏面用的比較多的是 etcd。

  • :微服務健康情況,運行狀況監控是如何作的?

  • :若是是使用容器化的部署方式,監控方面目前不少都是基於 Google 的 cAdvisor 來作的。

  • :請問微服務是否部署了多個實例,同服務的不一樣實例間是否有分佈式鎖來保護?

  • :若是須要保證服務之間的原子性,可使用分佈式鎖,但應該和微服務的初衷有點衝突。建議儘可能改爲異步通訊的方式,藉助 message queue 等來通訊。

  • :微服務的部署,老師比較推薦哪一種方式?藍綠、金絲雀,或者是其餘?

  • :咱們的業務是灰度。

  • :針對服務總線、API GateWay、OpenAPI之間的區別是什麼呢?您剛纔所講的服務發現屬於這裏面誰的範疇?

  • :服務總線是針對數據傳輸講的。API Gateway 的針對請求處理和分發的。OpenAPI 功能上應該差很少,主要是面向第三方平臺的開發者。API Gateway 除了終端(Web/iOS/Android)提供 API 功能以外,還提供了統一的入口、微服務接口聚合以及受權認證、後端服務負載均衡等功能。

  • :怎麼解決動態拓展Docker,網絡問題?

  • :要看具體是啥問題…… 網絡方面 Docker 官方有提供方案,k8s 也有,通常私有部署能夠直接使用開源的版本。

  • :若是應用已經基於Spark這樣的分佈式框架構建了,再想作微服務拆分有什麼比較好的方案嗎?

  • :我理解你跑在 Spark 上面的計算任務更依賴的是 Spark,而不是微服務的優點。所以若是你要考慮微服務話或者爲了充分利用容器雲平臺的能力,能夠考慮先把你依賴的 Spark 容器化,後面再考慮計算任務容器化的事情。

  • :以什麼標準來進行微服務顆粒度劃分?

  • :你們都說以業務的最小單元來拆分服務,但對業務的最小單元卻沒有統一的標準,也不可能有統一的標準,好比咱們作存儲業務的和你電商業務的標準就無法統一塊兒來。我我的的見解是,就像康威定律裏面說的,服務的複雜性決定了服務的大小和拆分的合理性,除了「以業務的最小單元來拆分」以外,維護某個微服務的團隊不該該太大。還有,拆分以後原本應該是儘可能解耦的,因此能夠看拆分以後是否帶來更復雜的異步通訊。

 

阿里P8 「佈道師」,談微服務的應用架構設計(附微服務教程)

原創不易,若是感受不錯,但願給個推薦!您的支持是我寫做的最大動力!版權聲明:做者:Ken企鵝交流羣:790845561 791372870騰訊課堂直播:https://ke.qq.com/course/144677?flowToken=1003848若是你對生活感受到了絕望,請不要氣餒。由於這樣只會讓你更加絕望! 所謂的但願每每都是在絕望中萌發的,因此,請不要放棄但願!

相關文章
相關標籤/搜索