每項微服務基礎設施都是一個平臺、一個系統(tǒng)、一個解決方案,如果要自己實現(xiàn),其過程和做業(yè)務系統(tǒng)類似,都需要經過需求分析、架構設計、開發(fā)、測試、部署上線等步驟,專欄里我來簡單介紹一下每個基礎設施的主要作用,更多詳細設計你可以參考 Spring Cloud 的相關資料(https://projects.spring.io/spring-cloud/)。
下面進入今天的內容,微服務架構最佳實踐的基礎設施篇。
自動化測試
微服務將原本大一統(tǒng)的系統(tǒng)拆分為多個獨立運行的“微”服務,微服務之間的接口數(shù)量大大增加,并且微服務提倡快速交付,版本周期短,版本更新頻繁。如果每次更新都靠人工回歸整個系統(tǒng),則工作量大,效率低下,達不到“快速交付”的目的,因此必須通過自動化測試系統(tǒng)來完成絕大部分測試回歸的工作。
自動化測試涵蓋的范圍包括代碼級的單元測試、單個系統(tǒng)級的集成測試、系統(tǒng)間的接口測試,理想情況是每類測試都自動化。如果因為團隊規(guī)模和人力的原因無法全面覆蓋,至少要做到接口測試自動化。
自動化部署
相比大一統(tǒng)的系統(tǒng),微服務需要部署的節(jié)點增加了幾倍甚至十幾倍,微服務部署的頻率也會大幅提升(例如,我們的業(yè)務系統(tǒng) 70% 的工作日都有部署操作),綜合計算下來,微服務部署的次數(shù)是大一統(tǒng)系統(tǒng)部署次數(shù)的幾十倍。這么大量的部署操作,如果繼續(xù)采用人工手工處理,需要投入大量的人力,且容易出錯,因此需要自動化部署的系統(tǒng)來完成部署操作。
自動化部署系統(tǒng)包括版本管理、資源管理(例如,機器管理、虛擬機管理)、部署操作、回退操作等功能。
配置中心
微服務的節(jié)點數(shù)量非常多,通過人工登錄每臺機器手工修改,效率低,容易出錯。特別是在部署或者排障時,需要快速增刪改查配置,人工操作的方式顯然是不行的。除此以外,有的運行期配置需要動態(tài)修改并且所有節(jié)點即時生效,人工操作是無法做到的。綜合上面的分析,微服務需要一個統(tǒng)一的配置中心來管理所有微服務節(jié)點的配置。
配置中心包括配置版本管理(例如,同樣的微服務,有 10 個節(jié)點是給移動用戶服務的,有 20 個節(jié)點給聯(lián)通用戶服務的,配置項都一樣,配置值不一樣)、增刪改查配置、節(jié)點管理、配置同步、配置推送等功能。
接口框架
微服務提倡輕量級的通信方式,一般采用 HTTP/REST 或者 RPC 方式統(tǒng)一接口協(xié)議。但在實踐過程中,光統(tǒng)一接口協(xié)議還不夠,還需要統(tǒng)一接口傳遞的數(shù)據(jù)格式。例如,我們需要指定接口協(xié)議為 HTTP/REST,但這還不夠,還需要指定 HTTP/REST 的數(shù)據(jù)格式采用 JSON,并且 JSON 的數(shù)據(jù)都遵循如下規(guī)范。

如果我們只是簡單指定了 HTTP/REST 協(xié)議,而不指定 JSON 和 JSON 的數(shù)據(jù)規(guī)范,那么就會出現(xiàn)這樣混亂的情況:有的微服務采用 XML,有的采用 JSON,有的采用鍵值對;即使同樣都是 JSON,JSON 數(shù)據(jù)格式也不一樣。這樣每個微服務都要適配幾套甚至幾十套接口協(xié)議,相當于把曾經由 ESB 做的事情轉交給微服務自己做了,這樣做的效率顯然是無法接受的,因此需要統(tǒng)一接口框架。
接口框架不是一個可運行的系統(tǒng),一般以庫或者包的形式提供給所有微服務調用。例如,針對上面的 JSON 樣例,可以由某個基礎技術團隊提供多種不同語言的解析包(Java 包、Python 包、C 庫等)。
API 網關
系統(tǒng)拆分為微服務后,內部的微服務之間是互聯(lián)互通的,相互之間的訪問都是點對點的。如果外部系統(tǒng)想調用系統(tǒng)的某個功能,也采取點對點的方式,則外部系統(tǒng)會非?!邦^大”。因為在外部系統(tǒng)看來,它不需要也沒辦法理解這么多微服務的職責分工和邊界,它只會關注它需要的能力,而不會關注這個能力應該由哪個微服務提供。
除此以外,外部系統(tǒng)訪問系統(tǒng)還涉及安全和權限相關的限制,如果外部系統(tǒng)直接訪問某個微服務,則意味著每個微服務都要自己實現(xiàn)安全和權限的功能,這樣做不但工作量大,而且都是重復工作。
綜合上面的分析,微服務需要一個統(tǒng)一的 API 網關,負責外部系統(tǒng)的訪問操作。
API 網關是外部系統(tǒng)訪問的接口,所有的外部系統(tǒng)接?系統(tǒng)都需要通過 API 網關,主要包括接入鑒權(是否允許接入)、權限控制(可以訪問哪些功能)、傳輸加密、請求路由、流量控制等功能。
服務發(fā)現(xiàn)
微服務種類和數(shù)量很多,如果這些信息全部通過手工配置的方式寫入各個微服務節(jié)點,首先配置工作量很大,配置文件可能要配幾百上千行,幾十個節(jié)點加起來后配置項就是幾萬幾十萬行了,人工維護這么大數(shù)量的配置項是一項災難;其次是微服務節(jié)點經常變化,可能是由于擴容導致節(jié)點增加,也可能是故障處理時隔離掉一部分節(jié)點,還可能是采用灰度升級,先將一部分節(jié)點升級到新版本,然后讓新老版本同時運行。不管哪種情況,我們都希望節(jié)點的變化能夠及時同步到所有其他依賴的微服務。如果采用手工配置,是不可能做到實時更改生效的。因此,需要一套服務發(fā)現(xiàn)的系統(tǒng)來支撐微服務的自動注冊和發(fā)現(xiàn)。
服務發(fā)現(xiàn)主要有兩種實現(xiàn)方式:自理式和代理式。
1. 自理式
自理式結構如下:

自理式結構就是指每個微服務自己完成服務發(fā)現(xiàn)。例如,圖中 SERVICE INSTANCE A 訪問 SERVICE REGISTRY 獲取服務注冊信息,然后直接訪問 SERVICE INSTANCE B。
自理式服務發(fā)現(xiàn)實現(xiàn)比較簡單,因為這部分的功能一般通過統(tǒng)一的程序庫或者程序包提供給各個微服務調用,而不會每個微服務都自己來重復實現(xiàn)一遍;并且由于每個微服務都承擔了服務發(fā)現(xiàn)的功能,訪問壓力分散到了各個微服務節(jié)點,性能和可用性上不存在明顯的壓力和風險。
2. 代理式
代理式結構如下:

代理式結構就是指微服務之間有一個負載均衡系統(tǒng)(圖中的 LOAD BALANCER 節(jié)點),由負載均衡系統(tǒng)來完成微服務之間的服務發(fā)現(xiàn)。
代理式的方式看起來更加清晰,微服務本身的實現(xiàn)也簡單了很多,但實際上這個方案風險較大。第一個風險是可用性風險,一旦 LOAD BALANCER 系統(tǒng)故障,就會影響所有微服務之間的調用;第二個風險是性能風險,所有的微服務之間的調用流量都要經過 LOAD BALANCER 系統(tǒng),性能壓力會隨著微服務數(shù)量和流量增加而不斷增加,最后成為性能瓶頸。因此 LOAD BALANCER 系統(tǒng)需要設計成集群的模式,但 LOAD BALANCER 集群的實現(xiàn)本身又增加了復雜性。
不管是自理式還是代理式,服務發(fā)現(xiàn)的核心功能就是服務注冊表,注冊表記錄了所有的服務節(jié)點的配置和狀態(tài),每個微服務啟動后都需要將自己的信息注冊到服務注冊表,然后由微服務或者 LOAD BALANCER 系統(tǒng)到服務注冊表查詢可用服務。
服務路由
有了服務發(fā)現(xiàn)后,微服務之間能夠方便地獲取相關配置信息,但具體進行某次調用請求時,我們還需要從所有符合條件的可用微服務節(jié)點中挑選出一個具體的節(jié)點發(fā)起請求,這就是服務路由需要完成的功能。
服務路由和服務發(fā)現(xiàn)緊密相關,服務路由一般不會設計成一個獨立運行的系統(tǒng),通常情況下是和服務發(fā)現(xiàn)放在一起實現(xiàn)的。對于自理式服務發(fā)現(xiàn),服務路由是微服務內部實現(xiàn)的;對于代理式服務發(fā)現(xiàn),服務路由是由 LOAD BALANCER 系統(tǒng)實現(xiàn)的。無論放在哪里實現(xiàn),服務路由核心的功能就是路由算法。常見的路由算法有:隨機路由、輪詢路由、最小壓力路由、最小連接數(shù)路由等。
服務容錯
系統(tǒng)拆分為微服務后,單個微服務故障的概率變小,故障影響范圍也減少,但是微服務的節(jié)點數(shù)量大大增加。從整體上來看,系統(tǒng)中某個微服務出故障的概率會大大增加。專欄第 34 期我在分析微服務陷阱時提到微服務具有故障擴散的特點,如果不及時處理故障,故障擴散開來就會導致看起來系統(tǒng)中很多服務節(jié)點都故障了,因此需要微服務能夠自動應對這種出錯場景,及時進行處理。否則,如果節(jié)點一故障就需要人工處理,投入人力大,處理速度慢;而一旦處理速度慢,則故障就很快擴散,所以我們需要服務容錯的能力。
常見的服務容錯包括請求重試、流控和服務隔離。通常情況下,服務容錯會集成在服務發(fā)現(xiàn)和服務路由系統(tǒng)中。
服務監(jiān)控
系統(tǒng)拆分為微服務后,節(jié)點數(shù)量大大增加,導致需要監(jiān)控的機器、網絡、進程、接口調用數(shù)等監(jiān)控對象的數(shù)量大大增加;同時,一旦發(fā)生故障,我們需要快速根據(jù)各類信息來定位故障。這兩個目標如果靠人力去完成是不現(xiàn)實的。舉個簡單例子:我們收到用戶投訴說業(yè)務有問題,如果此時采取人工的方式去搜集、分析信息,可能把幾十個節(jié)點的日志打開一遍就需要十幾分鐘了,因此需要服務監(jiān)控系統(tǒng)來完成微服務節(jié)點的監(jiān)控。
服務監(jiān)控的主要作用有:
實時搜集信息并進行分析,避免故障后再來分析,減少了處理時間。
服務監(jiān)控可以在實時分析的基礎上進行預警,在問題萌芽的階段發(fā)覺并預警,降低了問題影響的范圍和時間。
通常情況下,服務監(jiān)控需要搜集并分析大量的數(shù)據(jù),因此建議做成獨立的系統(tǒng),而不要集成到服務發(fā)現(xiàn)、API 網關等系統(tǒng)中。
服務跟蹤
服務監(jiān)控可以做到微服務節(jié)點級的監(jiān)控和信息收集,但如果我們需要跟蹤某一個請求在微服務中的完整路徑,服務監(jiān)控是難以實現(xiàn)的。因為如果每個服務的完整請求鏈信息都實時發(fā)送給服務監(jiān)控系統(tǒng),數(shù)據(jù)量會大到無法處理。
服務監(jiān)控和服務跟蹤的區(qū)別可以簡單概括為宏觀和微觀的區(qū)別。例如,A 服務通過 HTTP 協(xié)議請求 B 服務 10 次,B 通過 HTTP 返回 JSON 對象,服務監(jiān)控會記錄請求次數(shù)、響應時間平均值、響應時間最高值、錯誤碼分布這些信息;而服務跟蹤會記錄其中某次請求的發(fā)起時間、響應時間、響應錯誤碼、請求參數(shù)、返回的 JSON 對象等信息。
目前無論是分布式跟蹤還是微服務的服務跟蹤,絕大部分請求跟蹤的實現(xiàn)技術都基于 Google 的 Dapper 論文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》。
服務安全
系統(tǒng)拆分為微服務后,數(shù)據(jù)分散在各個微服務節(jié)點上。從系統(tǒng)連接的角度來說,任意微服務都可以訪問所有其他微服務節(jié)點;但從業(yè)務的角度來說,部分敏感數(shù)據(jù)或者操作,只能部分微服務可以訪問,而不是所有的微服務都可以訪問,因此需要設計服務安全機制來保證業(yè)務和數(shù)據(jù)的安全性。
服務安全主要分為三部分:接入安全、數(shù)據(jù)安全、傳輸安全。通常情況下,服務安全可以集成到配置中心系統(tǒng)中進行實現(xiàn),即配置中心配置微服務的接入安全策略和數(shù)據(jù)安全策略,微服務節(jié)點從配置中心獲取這些配置信息,然后在處理具體的微服務調用請求時根據(jù)安全策略進行處理。由于這些策略是通用的,一般會把策略封裝成通用的庫提供給各個微服務調用?;炯軜嬋缦拢?/p>

小結
今天我為你講了微服務架構相關的基礎設施的概要介紹和關鍵設計點,希望對你有所幫助。
這就是今天的全部內容,這一期的思考題很特別,給你一個由 10 位 Java 高級軟件工程師組成的開發(fā)團隊,采用自研的方式,完成所有的微服務基礎設施開發(fā),你預測需要多長時間?理由是什么呢?
歡迎你把答案寫到留言區(qū),和我一起討論。相信經過深度思考的回答,也會讓你對知識的理解更加深刻。(編輯亂入:精彩的留言有機會獲得豐厚福利哦?。?/p>