一文理解分布式開發(fā)中的服務(wù)治理
我們在分布式開發(fā)中經(jīng)常聽到的一個詞就是“服務(wù)治理”。在理解“服務(wù)治理”的概念之前讓我們先理解什么是分布式系統(tǒng),分布式系統(tǒng)之間如何通過RPC(Remote Procedure Call,遠(yuǎn)程過程調(diào)用)方式通信,以及如何解決RPC框架存在的問題,這樣才能真正地理解服務(wù)治理的核心思想。
分布式系統(tǒng)
分布式系統(tǒng)指的是通過網(wǎng)絡(luò)連接讓多臺計算機(jī)協(xié)同解決單臺計算機(jī)所不能解決的計算、存儲等問題,多臺計算機(jī)之間通過 RPC 方式通信。在使用分布式系統(tǒng)前,首要解決的問題是如何拆解當(dāng)前面臨的問題。通過使用多臺計算機(jī)分布式解決問題,讓分布式系統(tǒng)中的每臺機(jī)器都負(fù)責(zé)解決原問題的一個子集。一般來說,可以使用橫向拆分法或者縱向拆分法對復(fù)雜的系統(tǒng)進(jìn)行拆分。
橫向拆分:在無狀態(tài)系統(tǒng)中多部署幾個實例,通過負(fù)載均衡方式協(xié)調(diào)每個實例所負(fù)載的計算量。
縱向拆分:將一個大應(yīng)用拆分為多個小應(yīng)用(例如,將系統(tǒng)拆分為用戶、商品、訂單服務(wù)),每個小應(yīng)用都負(fù)責(zé)處理一部分業(yè)務(wù)。
然而,雖然通過拆分法解決了計算或存儲的問題,但是使用分布式技術(shù)進(jìn)行開發(fā)會引發(fā)比單體應(yīng)用更多的問題,比如網(wǎng)絡(luò)異常、數(shù)據(jù)一致性及分布式系統(tǒng)性能等。因此,在使用分布式架構(gòu)開發(fā)系統(tǒng)前,需要先深入理解分布式系統(tǒng)的概念和可能存在的異常。
1、分布式系統(tǒng)中的常見異常
服務(wù)器宕機(jī):服務(wù)器宕機(jī)是分布式架構(gòu)下最常見的異常之一。任何服務(wù)器都有可能發(fā)生故障,而且故障發(fā)生的類型、時間都不盡相同。所以,分布式系統(tǒng)一般允許部分服務(wù)器發(fā)生故障,但要求在部分服務(wù)器發(fā)生故障時不影響整個系統(tǒng)的正常使用。
網(wǎng)絡(luò)異常:服務(wù)器與服務(wù)器之間通過網(wǎng)絡(luò)通信,若在通信過程中出現(xiàn)消息丟失,則兩個節(jié)點之間無法進(jìn)行通信,會出現(xiàn)網(wǎng)絡(luò)分化、消息亂序等網(wǎng)絡(luò)問題。
分布式系統(tǒng)的三態(tài):如果某個節(jié)點向另一個節(jié)點發(fā)起RPC請求,比如節(jié)點A向節(jié)點B發(fā)送一個消息,節(jié)點B根據(jù)收到的消息完成某些操作,并將操作的結(jié)果通過消息返回給節(jié)點A,那么這個RPC請求的執(zhí)行結(jié)果可能有三種狀態(tài):成功、失敗、超時(未知)。我們將這三種狀態(tài)稱為分布式系統(tǒng)的三態(tài)。在設(shè)計架構(gòu)時需要考慮成功、失敗、超時(未知)這三種狀態(tài)的處理方式。
存儲的數(shù)據(jù)丟失:對于有狀態(tài)節(jié)點來說,數(shù)據(jù)丟失意味著狀態(tài)丟失。通常只能從其他節(jié)點讀取、恢復(fù)該存儲數(shù)據(jù)的狀態(tài)。
2、分布式系統(tǒng)的副本分類
分布式系統(tǒng)的副本指的是在分布式系統(tǒng)中為數(shù)據(jù)或服務(wù)提供的冗余。該副本可分為服務(wù)副本和數(shù)據(jù)副本兩種類型。
服務(wù)副本:多個節(jié)點提供某種相同的服務(wù),這種服務(wù)不依賴本地節(jié)點的存儲狀態(tài),是一種無狀態(tài)服務(wù)。
數(shù)據(jù)副本:在不同的節(jié)點上持久化同一份數(shù)據(jù)。當(dāng)出現(xiàn)某一個節(jié)點存儲的數(shù)據(jù)丟失時,可以從其他副本上讀取該數(shù)據(jù)。數(shù)據(jù)多副本是分布式系統(tǒng)解決數(shù)據(jù)丟失異常的唯一方法,因為數(shù)據(jù)被分散或者復(fù)制到不同的機(jī)器上,所以如何保證各臺主機(jī)之間數(shù)據(jù)的一致性,成為一個難點。
對于分布式系統(tǒng)而言,服務(wù)副本非常容易控制,由于服務(wù)本身具備無狀況特性,運(yùn)維人員可以動態(tài)增加或者減少服務(wù)副本的數(shù)量,而不會影響服務(wù)接口返回數(shù)據(jù)的正確性。數(shù)據(jù)副本分布在不同的計算機(jī)上,從技術(shù)角度來看,數(shù)據(jù)的一致性面臨著巨大的挑戰(zhàn)。數(shù)據(jù)副本的一致性通常具有以下幾種情況。
強(qiáng)一致性:任何時刻任何用戶或節(jié)點都可以讀到最近一次成功更新的副本數(shù)據(jù)。這是程度最高的一致性要求,也是實踐中最難實現(xiàn)的一致性。
弱一致性:系統(tǒng)并不保證進(jìn)程或者線程在任何時刻訪問數(shù)據(jù)都會返回最新的更新過的值。系統(tǒng)在數(shù)據(jù)成功寫入之后,不承諾立即讀到最新寫入的值,也不承諾最終多久之后可以讀到最新值。
最終一致性:數(shù)據(jù)一旦更新成功,各個副本上的數(shù)據(jù)最終將達(dá)到完全一致的狀態(tài),但需要一定的時間。
然而,分布式系統(tǒng)也存在一些復(fù)雜特性,比如分布式系統(tǒng)的三態(tài)性、異構(gòu)性、透明性、并發(fā)性、可擴(kuò)展性等。我們在應(yīng)用分布式系統(tǒng)的過程中要仔細(xì)斟酌這些特性的優(yōu)勢和副作用。
3.分布式系統(tǒng)的設(shè)計原則
異構(gòu)性:由于分布式系統(tǒng)基于不同的網(wǎng)絡(luò)、操作系統(tǒng)、計算機(jī)硬件和編程語言,因此必須考慮采用一種通用的網(wǎng)絡(luò)通信協(xié)議來屏蔽異構(gòu)系統(tǒng)之間的差異。開發(fā)人員一般選擇中間件來屏蔽這些差異。
透明性:分布式系統(tǒng)中任意組件的故障及主機(jī)的升級或遷移,對用戶來說都是透明的。
并發(fā)性:應(yīng)用分布式系統(tǒng)的目的是更好地共享資源,所以系統(tǒng)中的每個資源在并發(fā)環(huán)境下都必須是安全的。
可擴(kuò)展性:隨著業(yè)務(wù)量的增加,系統(tǒng)必須具備可擴(kuò)展性,以應(yīng)對因業(yè)務(wù)量增長而增加的外部流量。
故障獨(dú)立性:任何計算機(jī)都有可能發(fā)生故障,而且各計算機(jī)發(fā)生的故障類型不盡相同,發(fā)生故障的時間也各不相同。所以,分布式系統(tǒng)一般允許發(fā)生部分故障,而不影響整個系統(tǒng)的正常使用。
數(shù)據(jù)一致性:因為數(shù)據(jù)被分散或者復(fù)制到不同的機(jī)器上,所以需要保證各臺服務(wù)器之間數(shù)據(jù)的一致性。
負(fù)載均衡:由于分布式系統(tǒng)是多機(jī)協(xié)同工作的系統(tǒng),因此為了提高系統(tǒng)的整體效率和吞吐量,必須考慮最大化地發(fā)揮每個節(jié)點的作用,以最大化地利用資源,避免某個節(jié)點過載或者浪費(fèi)資源。
4.分布式系統(tǒng)的衡量指標(biāo)
系統(tǒng)的性能:系統(tǒng)每秒的事務(wù)處理能力,通常用TPS(Transactions Per Second)來衡量。
系統(tǒng)的可用性:系統(tǒng)在面對各種異常時可以正確提供服務(wù)的能力。該指標(biāo)可以用系統(tǒng)停服的時間與正常服務(wù)時間的比例來衡量,也可以用某功能的失敗次數(shù)與成功次數(shù)的比例來衡量。系統(tǒng)的可用性是分布式系統(tǒng)的重要指標(biāo),是系統(tǒng)容錯能力的體現(xiàn)。
系統(tǒng)的可擴(kuò)展性:分布式系統(tǒng)通過擴(kuò)展集群的機(jī)器規(guī)模來提高系統(tǒng)性能(增大接口吞吐量、降低接口延時、增大接口并發(fā)量)、存儲容量、計算能力的特性。
RPC框架
RPC(Remote Procedure Call,遠(yuǎn)程過程調(diào)用)是一種進(jìn)程間通信方式,也是一種技術(shù)思想。使用 RPC 技術(shù)時,允許本地程序通過網(wǎng)絡(luò)調(diào)用另一臺服務(wù)器上的函數(shù)或者方法,具體調(diào)用過程一般由 RPC 框架實現(xiàn),不用編碼實現(xiàn)。即無論是調(diào)用本地函數(shù)還是調(diào)用遠(yuǎn)程函數(shù),我們編寫的調(diào)用代碼在本質(zhì)上基本相同。
1.RPC框架的工作原理
RPC框架要向服務(wù)調(diào)用方和服務(wù)提供方屏蔽各類復(fù)雜性操作,比如負(fù)載均衡、序列化和反序列化、網(wǎng)絡(luò)重試、超時等,主要由客戶端、服務(wù)器端和注冊中心3種角色構(gòu)成,整體架構(gòu)如圖3-1所示。
客戶端(Client):調(diào)用遠(yuǎn)程服務(wù)的服務(wù)消費(fèi)方??蛻舳苏{(diào)用遠(yuǎn)程服務(wù)就像調(diào)用本地函數(shù)一樣,客戶端負(fù)責(zé)序列化、反序列化、連接池管理、負(fù)載均衡、故障轉(zhuǎn)移、超時管理、異步管理等。
服務(wù)器端(Server):暴露服務(wù)的服務(wù)提供方。服務(wù)器端如同實現(xiàn)一個本地函數(shù)一樣來實現(xiàn)遠(yuǎn)程服務(wù)提供,服務(wù)器端需要做收發(fā)包隊列、I/O線程、工作線程、序列化及反序列化等工作。
注冊中心:服務(wù)注冊與發(fā)現(xiàn)的注冊中心。
2.RPC調(diào)用說明
一次RPC調(diào)用流程主要由5部分組成,分別是客戶端、客戶端存根、服務(wù)器端存根、服務(wù)提供端和網(wǎng)絡(luò)傳輸,其調(diào)用流程如圖3-2所示。
客戶端:服務(wù)調(diào)用方。
客戶端存根:用于存放服務(wù)器端的地址信息,將客戶端的請求參數(shù)等信息打包成網(wǎng)絡(luò)消息,再通過網(wǎng)絡(luò)傳輸發(fā)送給服務(wù)器端。
服務(wù)器端存根:接收客戶端發(fā)送過來的請求消息并解包,然后調(diào)用本地服務(wù)處理。
服務(wù)提供端:服務(wù)的真正提供者。
網(wǎng)絡(luò)傳輸:底層數(shù)據(jù)傳輸,可以是TCP或HTTP。
服務(wù)治理
業(yè)務(wù)在剛開始時都是單體應(yīng)用,隨著用戶量和訪問量的增加,在架構(gòu)層面會發(fā)生變化,逐步由單體應(yīng)用開發(fā)轉(zhuǎn)為分布式應(yīng)用開發(fā),比如把單體應(yīng)用中的每個模塊都按照特定的方法拆分成一組獨(dú)立的服務(wù),服務(wù)與服務(wù)之間通過HTTP或者RPC方式調(diào)用。隨著業(yè)務(wù)量的逐步增加,服務(wù)的數(shù)量也逐步增加。這時維護(hù)服務(wù)的URL地址就變得非常麻煩,所以需要設(shè)計一套系統(tǒng)來統(tǒng)一管理每個服務(wù)所對應(yīng)的URL地址。這套系統(tǒng)就叫作注冊中心。當(dāng)有多個服務(wù)時,消費(fèi)者需要根據(jù)規(guī)則來調(diào)用相關(guān)服務(wù),實現(xiàn)軟負(fù)載均衡,以達(dá)到資源利用率最大化的目的。因此,服務(wù)注冊、服務(wù)發(fā)現(xiàn)、負(fù)載均衡、流量削峰、版本兼容、服務(wù)熔斷、服務(wù)降級、服務(wù)限流等方面的問題,都是因服務(wù)拆分所引發(fā)的一系列問題。如何解決這些問題,讓服務(wù)更穩(wěn)定地運(yùn)行,就叫作服務(wù)治理。
總體來說,服務(wù)治理指的是企業(yè)為了確保事情順利完成而實施的內(nèi)容,包括最佳實踐、架構(gòu)原則、治理規(guī)程、規(guī)律及其他決定性的因素。下面針對服務(wù)治理過程中的各個環(huán)節(jié)做相關(guān)說明。
(1)服務(wù):它是分布式架構(gòu)下的基礎(chǔ)單元,包括一個或一組軟件功能,其目的是不同的客戶端通過網(wǎng)絡(luò)獲取相應(yīng)的數(shù)據(jù),而不用關(guān)注底層實現(xiàn)的具體細(xì)節(jié)。以用戶服務(wù)為例,當(dāng)客戶端調(diào)用用戶服務(wù)的注冊功能時,注冊信息會被寫入數(shù)據(jù)庫、緩存并發(fā)送消息來通知其他關(guān)注注冊事件的系統(tǒng),但是調(diào)用方并不清楚服務(wù)的具體處理邏輯。
(2)注冊中心:它是微服務(wù)架構(gòu)中的“通訊錄”,記錄了服務(wù)和服務(wù)地址的映射關(guān)系,主要涉及服務(wù)的提供者、服務(wù)注冊中心和服務(wù)的消費(fèi)者。在數(shù)據(jù)流程中,服務(wù)提供者在啟動服務(wù)之后將服務(wù)注冊到注冊中心;服務(wù)消費(fèi)者(或稱為服務(wù)消費(fèi)方)在啟動時,會從注冊中心拉取相關(guān)配置,并將其放到緩存中。注冊中心的優(yōu)勢在于解耦了服務(wù)提供者和服務(wù)消費(fèi)者之間的關(guān)系,并且支持彈性擴(kuò)容和縮容。當(dāng)服務(wù)需要擴(kuò)容時,只需要再部署一個該服務(wù)。當(dāng)服務(wù)成功啟動后,會自動被注冊到注冊中心,并推送給消費(fèi)者。
(3)服務(wù)注冊與發(fā)布:服務(wù)實例在啟動時被加載到容器中,并將服務(wù)自身的相關(guān)信息,比如接口名稱、接口版本、IP地址、端口等注冊到注冊中心,并使用心跳機(jī)制定期刷新當(dāng)前服務(wù)在注冊中心的狀態(tài),以確認(rèn)服務(wù)狀態(tài)正常,在服務(wù)終止時將其從注冊表中刪除。服務(wù)注冊包括自注冊模式和第三方注冊模式這兩種模式。
◎自注冊模式:服務(wù)實例負(fù)責(zé)在服務(wù)注冊表中注冊和注銷服務(wù)實例,同時服務(wù)實例要發(fā)送心跳來保證注冊信息不過期。其優(yōu)點是,相對簡單,無須其他系統(tǒng)功能的支持;缺點是,需要把服務(wù)實例和服務(wù)注冊表聯(lián)系起來,必須在每種編程語言和框架內(nèi)部實現(xiàn)注冊代碼。
◎第三方注冊模式:服務(wù)實例由另一個類似的服務(wù)管理器負(fù)責(zé)注冊,服務(wù)管理器通過查詢部署環(huán)境或訂閱事件來跟蹤運(yùn)行服務(wù)的改變。當(dāng)管理器發(fā)現(xiàn)一個新的可用服務(wù)時,會向注冊表注冊此服務(wù),同時服務(wù)管理器負(fù)責(zé)注銷終止的服務(wù)實例。第三方注冊模式的主要優(yōu)勢是服務(wù)與服務(wù)注冊表是分離的,無須為每種編程語言和架構(gòu)都完成服務(wù)注冊邏輯。相應(yīng)地,服務(wù)實例是通過一個集中化管理的服務(wù)進(jìn)行管理的;缺點是,需要一個高可用系統(tǒng)來支撐。
(4)服務(wù)發(fā)現(xiàn):使用一個注冊中心來記錄分布式系統(tǒng)中全部服務(wù)的信息,以便其他服務(wù)快速找到這些已注冊的服務(wù)。其目前有客戶端發(fā)現(xiàn)模式和服務(wù)器端發(fā)現(xiàn)模式這兩種模式。
客戶端發(fā)現(xiàn)模式:客戶端從服務(wù)注冊服務(wù)中查詢所有可用服務(wù)實例的地址,使用負(fù)載均衡算法從多個服務(wù)實例中選擇一個,然后發(fā)出請求。其優(yōu)勢在于客戶端知道可用服務(wù)注冊表的信息,因此可以定義多種負(fù)載均衡算法,而且負(fù)載均衡的壓力都集中在客戶端。
服務(wù)器端發(fā)現(xiàn)模式:客戶端通過負(fù)載均衡器向某個服務(wù)提出請求,負(fù)載均衡器從服務(wù)注冊服務(wù)中查詢所有可用服務(wù)實例的地址,將每個請求都轉(zhuǎn)發(fā)到可用的服務(wù)實例中。與客戶端發(fā)現(xiàn)一樣,服務(wù)實例在服務(wù)注冊表中注冊或者注銷。我們可以將HTTP服務(wù)、Nginx的負(fù)載均衡器都理解為服務(wù)器端發(fā)現(xiàn)模式。其優(yōu)點是,客戶端無須關(guān)注發(fā)現(xiàn)的細(xì)節(jié),可以減少客戶端框架需要完成的服務(wù)發(fā)現(xiàn)邏輯;客戶端只需簡單地向負(fù)載均衡器發(fā)送請求。其缺點是,在服務(wù)器端需要配置一個高可用的負(fù)載均衡器。
(5)流量削峰:使用一些技術(shù)手段來削弱瞬時的請求高峰,讓系統(tǒng)吞吐量在高峰請求下可控,也可用于消除毛刺,使服務(wù)器資源的利用更加均衡、充分。常見的削峰策略有隊列、限頻、分層過濾、多級緩存等。
(6)版本兼容:在升級版本的過程中,需要考慮升級版本后新的數(shù)據(jù)結(jié)構(gòu)能否理解和解析舊的數(shù)據(jù),新協(xié)議能否理解舊的協(xié)議并做出預(yù)期內(nèi)合適的處理。這就需要在服務(wù)設(shè)計過程中做好版本兼容工作。
(7)服務(wù)熔斷:其作用類似于家用的保險絲。當(dāng)某服務(wù)出現(xiàn)不可用或響應(yīng)超時的情況時,已經(jīng)達(dá)到系統(tǒng)設(shè)定的閾值,為了防止整個系統(tǒng)出現(xiàn)雪崩,會暫時停止對該服務(wù)的調(diào)用。
(8)服務(wù)降級:在服務(wù)器壓力劇增的情況下,根據(jù)當(dāng)前業(yè)務(wù)情況及流量對一些服務(wù)和頁面有策略性地降級,以此釋放服務(wù)器資源,保證核心任務(wù)的正常運(yùn)行。降級時往往會指定不同的級別,面對不同的異常等級執(zhí)行不同的處理。
(9)服務(wù)限流:服務(wù)限流可以被認(rèn)為是服務(wù)降級的一種。它通過限制系統(tǒng)的輸入和輸出流量來達(dá)到保護(hù)系統(tǒng)的目的。一般來說,系統(tǒng)的吞吐量是可以被測算的。為了保證系統(tǒng)的穩(wěn)定運(yùn)行,一旦達(dá)到閾值,就需要限制流量。限制措施有延遲處理、拒絕處理或者部分拒絕處理等。
(10)負(fù)載均衡策略:它是用于解決一臺機(jī)器無法處理所有請求而產(chǎn)生的一種算法。當(dāng)集群里的1臺或者多臺服務(wù)器不能響應(yīng)請求時,負(fù)載均衡策略會通過合理分?jǐn)偭髁?,讓更多的服?wù)器均衡處理流量請求,不會因某一高峰時刻流量大而導(dǎo)致單個服務(wù)器的 CPU或內(nèi)存急劇上升。