一文讀懂微服務與服務網格——“WHAT, WHY and HOW TO DO”

作者注:
聯繫方式 [email protected] || github.com/XinyaoTian
新人入行,非常期待能與各位大牛們討論,感謝各位的閱讀,希望對您有所幫助。

一切都要從雲計算和容器技術的出現說起...

相信每一位老道的開發者和軟件工程師們都會有過,曾經( 也許現在仍然 )被龐大且複雜的軟件系統所支配的恐懼。隨着軟件版本的迭代和開發團隊人員規模的擴大,曾經那個小巧別緻、設計精良的軟件或應用一去不返,如今已經變得遍地狼藉,慘不忍睹——混亂的接口、不規範的調用、像貼狗皮膏藥一般貼上去的新功能組件……曾經那個賞心悅目的應用,如今看了就反胃。這一切都預示着一個問題:開發軟件的方式需要改變。

縱使有那麼多種軟件開發模式,但如果不能從底層技術上實現對設計的約束,問題將會隨着時間的推移,最終暴露出來。譬如“高內聚,低耦合”的設計理念,如果不能從底層就實現模塊間的隔離,而依靠開發時的技巧和經驗,那麼最終這個軟件依舊會變得一團糟( 因爲團隊會有新人的加入、即使經驗老道的開發者也會有頭腦發昏的時候…… )。因此,“不這麼寫就無法運行”這樣的硬性要求就很有必要了。

雲計算和容器技術的出現,非常及時地幫助我們解決了這一難題。雲計算的高彈性和按需分配、容器技術的快速啓停和隔離,都很好的幫助了我們減少運維開銷,且對於不同模塊實現操作系統級別的隔離。在這兩種關鍵技術出現前後,軟件架構的差別如下圖所示:
圖片描述

( 上圖: 單體應用 與 微服務應用 )

以 Web 應用爲例,按照之前的開發方式,我們往往會選用一個功能齊全但相當複雜的開發框架( 比如JAVA開發常用的 SpringBoot ),然後在這個框架的基礎上,根據開發經驗和框架的功能將整個應用分層( 比如最常用的表示層、業務邏輯層和數據資源層的分層方法 ),之後根據需求分析得出的各個功能,通過不同目錄、文件和函數的方式分別開發,最終一個完整的 Web 應用被開發出來。其過程如下圖所示。
圖片描述

( 上圖: 基於框架的軟件開發架構網格 )

通過使用框架,我們把軟件在層次上分爲三層,而之後的每個功能,就相當於縱向地添加一個新列。如果以這種方式看待一個應用,那麼我們就可以將任何基於這種開發方法的應用看作一個3行n列的表格或矩陣了。

然而,這種非常普及的開發方式仍然有一些問題...

雖然這種開發方式已經非常普及,非常成熟,但其仍有許多有待改進的地方。比如:

依賴和庫過於龐雜。理想情況下,我們希望針對每一個模塊,單獨管理其相應的依賴和庫,而不是以整個應用作爲單位來管理。

無法改變層次結構。某種層次結構對於某些業務需求來說很棒,但對於另外一些也許就顯得不那麼合適了。使用這種方式開發,幾乎所有功能都要遵從這種既定的層次開發( 比如寫 UI、寫業務邏輯、寫數據庫層 )。而對於目前日漸快速的迭代和敏捷的開發思想,我們需要一種更加靈活輕便的方式進行開發。

無法實現跨語言開發。我們知道,幾乎每種編程語言都有自己最擅長的領域。也許某些功能選用其他編程語言的開發效率更高,運行效果更好。然而,使用這種方式我們往往只能使用選定的框架所支持的語言。

模塊的獨立性不足。單純通過函數和文件來進行隔離,隔離性仍然不夠。一個疏忽或是加急上線就會讓之前良好的高內聚低耦合的良好軟件結構灰飛煙滅。因此,我們需要更加底層的機制來硬性約束我們實現“高內聚低耦合”,把“應該這麼做”變爲“必須這麼做”。

而伴隨着雲計算和容器技術的發展,微服務的出現,恰巧將這些問題迎刃而解。
圖片描述

( 上圖: 容器技術的基本層次結構 )

先來說說容器技術的代表 —— Docker

Docker 可以看作是輕量級的虛擬機——它可以通過“容器鏡像”快速啓動和停止預先配置好的相應運行環境。每一個容器都可以被看作一個獨立的操作系統,相互隔離,互不干擾。因此,藉助docker 我們就可以針對一個應用中不同的功能,爲其獨立定製運行環境,獨立裝載依賴和工具庫,獨立運行獨立停止,獨立升級,每個功能可以使用其最適合的編程語言進行開發,也將整個應用拘泥於一種框架了。利用 docker 將每個模塊在操作系統層面進行隔離,對於每個模塊都可以獨立管理其生命週期了,這就是“微服務”中“微”字的具體含義。

微服務開發的重點

基於這種開發方式,每個功能模塊可以被獨立開發,獨立部署,獨立運行,獨立進行版本控制,等等。而對於規模比較龐大的系統來說,這種利用微服務架構所開發的應用,其天然的優勢就更能體現出來了——即每個模塊可以獨立的團隊由單獨負責。因此,微服務開發中的第一個重點,就是要有非常明確的需求,以及一個經驗豐富的架構師,在設計之初就對各個功能模塊進行合理的規劃和拆分。

在整個應用設計之初由總設計師或架構師設計好各個功能模塊後,第二個重點就來了:設計微服務中各個模塊間的調用接口——通常由 Rest API 或者 gRPC 組成——來負責模塊之間的交互,這就是微服務的第二個重點。良好的接口設計將會使你的應用結構清晰,開發起來事半功倍。而且每個獨立團隊在開發時都能感受到明顯的模塊邊界,且可以放心利用模擬數據和測試數據進行開發( 只要符合接口規則的數據就能用,不用操心其他模塊是如何實現的 ),從而真正實現每個團隊富有效率的並行開發。

利用微服務架構開發除了上述好處之外,在運維方面的優勢也非常直觀——我們可以清晰地觀測到整個系統的資源瓶頸在何處( 哪個容器的資源開銷最大 ),從而實現有針對性的“定向擴縮容”。利用微服務架構前後的擴縮容機制如下圖所示意。

圖片描述

( 上圖: 單體應用和微服務應用最直觀的差別:定向擴縮容 示意圖 )

將龐大的單體應用逐步改造成微服務應用

在看完上面的介紹後,相信飽受單體應用折磨的各位讀者已經對微服務開發已經躍躍欲試了。但是,對於一個正在運行並使用的應用來說,完完全全從零開始開發並不現實。對於一個已經成熟並正在使用的單體應用系統來說,我們可以通過自己的努力,將一個單體應用在幾次迭代過程中,逐漸改變爲微服務應用。如何辦到呢?下面放一張圖片來幫助您激發靈感:

圖片描述

( 上圖: 熱帶雨林中的參天大樹與附着在其上的藤蔓 )

沒錯,就像您所想到的那樣:在這幅圖中,龐大的樹木代表着我們原有的單體項目,而樹外所覆蓋着的藤蔓就象徵着微服務組件。在將您的單體應用微服務化時,也可以採用這種方式,即:新的功能使用微服務架構來開發,通過對原有的單體應用暴露 IP 和端口號的方式供其進行調用和使用。

利用這種方式,您之後新開發的功能所對應的軟件實體就都是基於微服務架構的了。這樣隨着時間的推移和版本的逐漸迭代,採用微服務架構所開發的部分所佔比例越來越大,最後原來的單體應用也逐漸變爲了整個應用中的一個獨立服務,您的軟件架構就徹底地完成了微服務化。

這種改造方式來源於 Chris Richardson 的系列博文中的一篇,如果您對這方面內容感興趣的話,歡迎您移步其博客一探究竟( 博客的中文翻譯鏈接: https://www.jianshu.com/p/29f... )。由於內容過多,在此不再展開討論一一贅述。

Happy Ending,十全十美了?

顯然不是,技術的發展從來沒有止境,也不存在止鏡。微服務的出現,雖然解決了傳統軟件開發結構龐大、模塊複雜等諸多難點,但是解決了原有的問題後,新的問題又浮出了水面:微服務應用的每個基本單元之間調用關係複雜、網絡位置處於動態變化、且每個組件的生命週期都各自獨立,因此難以實現統一的管理。

這裏說的可能有些抽象,那麼就爲大家舉一個小例子:請大家設想一個簡單的場景:每一個微服務組件都有一個自己獨有的網絡位置( 在因特網中就是我們最常用的 IP 和端口號 ),以此來唯一確定一個服務;其他服務若想調用本服務,就需要知道該服務的 IP 和端口號,以此對其發送網絡請求。

細心的朋友可能已經察覺到問題了:對於一個微服務架構的應用場景,微服務的每一個組件都是不斷處於動態擴縮容的狀態中的,可能上一秒這個 IP 和端口號還對應着相應的組件,下一秒這個組件就由於當前訪問量的下降而被節約成本,自動地縮容釋放掉了。如果這時其他服務再來訪問這個 IP 和端口號,那一定會出現找不到服務等各種故障。

圖片描述

( 上圖: 多變的網絡位置是微服務管理中的一大難題 )

架構改變所帶來的諸如此類的問題還有許多,在此就不一一列舉了。準備將自己的軟件架構進行微服務化的朋友們需要三思:改變一種軟件架構可能會解決許多曾經的架構所存在的問題,但同時也會帶來很多原有架構不會出現的新問題。

不過幸好微服務架構已經有不少國內外的大公司和優秀團隊作爲先驅,率先摸着石頭過了一次河,並且告訴了我們許多過河的寶貴經驗,甚至已經有許多工具和開源項目被開發出來,幫助我們解決剛纔分析到的種種問題了。

在目前種種微服務場景的解決方案中,有兩種是使用最爲普遍、同時也廣受好評的。它們分別是較早出現的 Spring Cloud 框架,以及近幾年微服務領域最爲流行的 Service Mesh 微服務管理框架。由於 Service Mesh 所帶來的“業務代碼零侵入”、“直接與容器管理框架(如 K8s )集成”等諸多優點,因此基於 Service Mesh 的微服務開發和蔚雲方式正在逐漸成爲主流,特別是 Google 宣佈了其 Istio 項目可以與 K8s 完美集成後,國內外社區的開發者對 Service Mesh 的發展更是翹首以盼。下面就對 Service Mesh 進行一下簡單的介紹。

何爲 "Service Mesh"

“A service mesh is a dedicated infrastructure layer for handling service-to-service communication. “ —— William Morgan( Founder of Service Mesh )

Service Mesh 是一個專注於處理服務間通信的基礎設施層。
雲原生應用有着複雜的服務拓撲,而 Service Mesh 保證請求可以在這些拓撲中可靠地穿梭。在實際應用當中,Service Mesh 通常是由一系列輕量級的網絡代理組成的,它們與應用程序部署在一起,但應用程序不需要知道它們的存在。

圖片描述

( 上圖: Service Mesh 示意圖——幫助您管理錯誤複雜的微服務應用 )

技術起源與出現背景

Service Mesh 的概念最早由前 twitter 的基礎設施工程師 William Morgan 於 2017 年 4 月 25 日提出。雖然在此之前,微服務領域也有類似的概念被提出或用於開發項目,但在業界始終沒有一個統一的名稱。 William Morgan 在自己的博文 "What’s a service mesh? And why do I need one?" 中正式給 Service Mesh 做出了權威的定義。至此,"Service Mesh" 這個名詞正式出現在各大公司以及技術社區的視野中。

隨着雲計算的普及,越來越多的開發者和企業開始使用“微服務”的開發模式。這種開發模式擁有諸如耦合度低、跨語言開發、更小粒度擴容等許多優勢,但同樣也面臨着許多挑戰,就如我們上文所分析的那樣。

Service Mesh 的發展

Service Mesh 從出現至今總共經歷了三個階段:微服務初期、Sidecar 時期和 Service Mesh 時期。

微服務初期

在微服務初期( 2015年前 )開發微服務應用的過程中,我們需要重複性地處理一系列基礎工作,比如:服務註冊、服務發現、得到服務實例後的負載均衡、熔斷機制等。這些工作在 Service Mesh 出現之前統統都要開發人員在項目中用代碼解決並實現,導致應用程序中加入了大量的非功能性代碼。即使使用類似 Netflix OSS 的庫和 Spring Cloud 的框架,開發人員依然面臨着需掌握內容多、技術門檻高等諸多困難。

Sidecar 的出現

圖片描述

( 上圖: Sidecar ,中文意思爲摩托車的跨鬥,不由讚歎命名的非常生動 )

"Sidecar" 這個詞,本人使用 Google 搜索引擎同時檢索 sidecar 和 microservices 這兩個關鍵字並按時間順序排序,最早出現的檢索結果是在 2014 年 5 月 14 日的這篇演講中。根據本人查閱的資料顯示,"Sidecar" 這個名詞最早由 Netflix 提出並被用於 Eureka 項目。由於這個項目的廣泛應用,故在此之後,凡是微服務中“用於端對端通信的、被單獨分離出來的“組件,就都被稱爲 "Sidecar" 了。

仔細分析上述一系列的重複性工作,我們可以發現,這些工作幾乎全部集中在處理各個服務間的通信問題。那麼,爲何我們不把這些工作從業務邏輯中抽離出來,使其專注於服務間通信,並形成單獨的組件呢?
Sidecar 模式,即在微服務中將關於服務通訊的功能抽離出來,並作爲一個單獨的組件運行在微服務中。這種在微服務中獨立負責端對端通信的組件,我們稱之爲 Sidecar 。這種在微服務中將業務邏輯與服務通信解藕,並分離爲兩個獨立運行組件的做法,正是 Service Mesh 概念的雛形。
但在這個階段,每個微服務中的 Sidecar 還無法通用,即這個微服務的 Sidecar 沒有辦法拆出來給另一個微服務使用。

Service Mesh 的提出

Service Mesh 在 Sidecar 模式的基礎上更進一步。Service Mesh 的定義——一個專注於處理服務間通信的基礎設施層——站在開發者的角度來講,就是在每一個微服務中將用於通信的部分從業務中徹底解藕,應用程序甚至不需要知道它們的存在。在 Service Mesh 中,每個微服務至少含有兩個組件:一個用於處理業務功能的“應用程序”和一個專職處理服務間通信的“ Sidecar ”( 類似網絡代理 )。

Service Mesh 的願景是希望開發者再也不需要將精力花費在服務通信上。服務通信由每個微服務的 Sidecar 負責,而 Sidecar 由專門的項目來接管。目前,許多被熟知的項目都可以被我們當作 Sidecar 來運用,比如 Envoy 、 HAProxy 和 Nginx 。

使用了 Service Mesh 之後,開發團隊和運維團隊就可以更加明確的劃清自己的職責範圍——開發團隊專注於業務的開發,而運維團隊只需關注微服務中的 Sidecar 就可以明確地瞭解到每個微服務的健康情況和各種指標。

圖片描述

( 上圖: “Service Mesh”一詞成爲技術術語,首次在公衆場合亮相 )

Service Mesh 的設計理念和作用

隨着雲原生應用的崛起,Service Mesh 逐漸成爲一個獨立的基礎設施層。在雲原生模型裏,一個應用可以由數百個服務組成,每個服務可能有數千個實例,而每個實例可能會持續地發生變化。服務間通信不僅異常複雜,而且也是運行時行爲的基礎。管理好服務間通信對於保證端到端的性能和可靠性來說是非常重要的。

Service Mesh 實際上就是處於 TCP/IP 之上的一個抽象層,它假設底層的 L3/L4 網絡能夠點對點地傳輸字節(當然,它也假設網絡環境是不可靠的,所以 Service Mesh 也必須具備處理網絡故障的能力)。

從某種程度上說,Service Mesh 有點類似 TCP/IP 。TCP 對網絡端點間傳輸字節的機制進行了抽象,而Service Mesh則是對服務節點間請求的路由機制進行了抽象。Service Mesh 不關心消息體是什麼,也不關心它們是如何編碼的。應用程序的目標是“將某些東西從A傳送到B”,而 Service Mesh 所要做的就是實現這個目標,並處理傳送過程中可能出現的任何故障。

與TCP不同的是,Service Mesh有着更高的目標:爲應用運行時提供統一的、應用層面的可見性和可控性。通過每個微服務中的 Sidecar ,Service Mesh 得以將服務間通信從底層的基礎設施中分離出來,讓它成爲整個生態系統的一等公民——它不再是單純的基礎設施,更可以被監控、託管和控制。

Service Mesh 的未來

儘管 Service Mesh 在雲原生系統方面的應用已經有了快速的增長,但仍然存在巨大的提升空間。服務發現和訪問策略在雲原生環境中仍顯初級,而 Service Mesh 毫無疑問將成爲這方面不可或缺的基礎。就像 TCP/IP 作爲互聯網的基礎一樣,Service Mesh 將在微服務的底層基礎設施這條路上更進一步。

總結及展望

本文主要介紹了兩個關鍵點:當下最爲流行的一種軟件開發架構——微服務架構、以及解決微服務架構帶來的種種問題的微服務管理模型——Service Mesh(服務網格)模型。

在使用微服務架構開發應用的初期,大家一定會沉醉於其清晰的模塊邊界和獨立運行所帶來的種種便利。然而,這並不是說微服務應用就已經十全十美了。隨着一個龐大的單體應用被拆分爲細碎的各個微小模塊,如果對它們進行有效的管理就成爲了新的挑戰。畢竟,一箇中等體量的應用被微服務化後,幾百個小模塊同時運行是常有的事兒。那麼,如何控制服務之間的調用?如何定位這些服務( 你知道,在這種場景下手動修改配置文件指定其他服務的 IP 和 port 已經不現實了 )?如何將出現錯誤的應用及時熔斷?這都是亟待我們解決的事情,也是目前微服務架構所發展的主要方向。

在熟練運用 Docker 後,我們可以繼續去學習 Kubernetes,一款由 Google 和 IBM 共同開發的開源“容器集羣管理框架”,類似於控制容器的“操作系統”。

而微服務所面臨的上述種種問題,目前我們可以藉助同樣由 Google 開發的 Istio(服務網格的一種) 來解決,諸如服務註冊、服務發現、服務治理、流量管理和容錯機制等等。其基本層次關係如下圖所示。

圖片描述

( 上圖: 自己整理的“目前微服務架構的技術棧”,希望各位讀者有所幫助 )

希望本篇文章能夠成爲您開展微服務相關工作的參考,爲您瞭解爲服務理念、轉型微服務架構提供幫助。文章中如果存在遺漏或錯誤,也非常歡迎您指出,非常期待與您的交流與討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章