一文理解分布式開發(fā)中的服務治理
我們在分布式開發(fā)中經(jīng)常聽到的一個詞就是“服務治理”。在理解“服務治理”的概念之前讓我們先理解什么是分布式系統(tǒng),分布式系統(tǒng)之間如何通過RPC(Remote Procedure Call,遠程過程調(diào)用)方式通信,以及如何解決RPC框架存在的問題,這樣才能真正地理解服務治理的核心思想。
分布式系統(tǒng)指的是通過網(wǎng)絡連接讓多臺計算機協(xié)同解決單臺計算機所不能解決的計算、存儲等問題,多臺計算機之間通過 RPC 方式通信。在使用分布式系統(tǒng)前,首要解決的問題是如何拆解當前面臨的問題。通過使用多臺計算機分布式解決問題,讓分布式系統(tǒng)中的每臺機器都負責解決原問題的一個子集。一般來說,可以使用橫向拆分法或者縱向拆分法對復雜的系統(tǒng)進行拆分。
◎橫向拆分:在無狀態(tài)系統(tǒng)中多部署幾個實例,通過負載均衡方式協(xié)調(diào)每個實例所負載的計算量。
◎縱向拆分:將一個大應用拆分為多個小應用(例如,將系統(tǒng)拆分為用戶、商品、訂單服務),每個小應用都負責處理一部分業(yè)務。
然而,雖然通過拆分法解決了計算或存儲的問題,但是使用分布式技術(shù)進行開發(fā)會引發(fā)比單體應用更多的問題,比如網(wǎng)絡異常、數(shù)據(jù)一致性及分布式系統(tǒng)性能等。因此,在使用分布式架構(gòu)開發(fā)系統(tǒng)前,需要先深入理解分布式系統(tǒng)的概念和可能存在的異常。
1、分布式系統(tǒng)中的常見異常
◎服務器宕機:服務器宕機是分布式架構(gòu)下最常見的異常之一。任何服務器都有可能發(fā)生故障,而且故障發(fā)生的類型、時間都不盡相同。所以,分布式系統(tǒng)一般允許部分服務器發(fā)生故障,但要求在部分服務器發(fā)生故障時不影響整個系統(tǒng)的正常使用。
◎網(wǎng)絡異常:服務器與服務器之間通過網(wǎng)絡通信,若在通信過程中出現(xiàn)消息丟失,則兩個節(jié)點之間無法進行通信,會出現(xiàn)網(wǎng)絡分化、消息亂序等網(wǎng)絡問題。
◎分布式系統(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é)點讀取、恢復該存儲數(shù)據(jù)的狀態(tài)。
2、分布式系統(tǒng)的副本分類
分布式系統(tǒng)的副本指的是在分布式系統(tǒng)中為數(shù)據(jù)或服務提供的冗余。該副本可分為服務副本和數(shù)據(jù)副本兩種類型。
◎服務副本:多個節(jié)點提供某種相同的服務,這種服務不依賴本地節(jié)點的存儲狀態(tài),是一種無狀態(tài)服務。
◎數(shù)據(jù)副本:在不同的節(jié)點上持久化同一份數(shù)據(jù)。當出現(xiàn)某一個節(jié)點存儲的數(shù)據(jù)丟失時,可以從其他副本上讀取該數(shù)據(jù)。數(shù)據(jù)多副本是分布式系統(tǒng)解決數(shù)據(jù)丟失異常的唯一方法,因為數(shù)據(jù)被分散或者復制到不同的機器上,所以如何保證各臺主機之間數(shù)據(jù)的一致性,成為一個難點。
對于分布式系統(tǒng)而言,服務副本非常容易控制,由于服務本身具備無狀況特性,運維人員可以動態(tài)增加或者減少服務副本的數(shù)量,而不會影響服務接口返回數(shù)據(jù)的正確性。數(shù)據(jù)副本分布在不同的計算機上,從技術(shù)角度來看,數(shù)據(jù)的一致性面臨著巨大的挑戰(zhàn)。數(shù)據(jù)副本的一致性通常具有以下幾種情況。
◎強一致性:任何時刻任何用戶或節(jié)點都可以讀到最近一次成功更新的副本數(shù)據(jù)。這是程度最高的一致性要求,也是實踐中最難實現(xiàn)的一致性。
◎弱一致性:系統(tǒng)并不保證進程或者線程在任何時刻訪問數(shù)據(jù)都會返回最新的更新過的值。系統(tǒng)在數(shù)據(jù)成功寫入之后,不承諾立即讀到最新寫入的值,也不承諾最終多久之后可以讀到最新值。
◎最終一致性:數(shù)據(jù)一旦更新成功,各個副本上的數(shù)據(jù)最終將達到完全一致的狀態(tài),但需要一定的時間。
然而,分布式系統(tǒng)也存在一些復雜特性,比如分布式系統(tǒng)的三態(tài)性、異構(gòu)性、透明性、并發(fā)性、可擴展性等。我們在應用分布式系統(tǒng)的過程中要仔細斟酌這些特性的優(yōu)勢和副作用。
3.分布式系統(tǒng)的設(shè)計原則
◎異構(gòu)性:由于分布式系統(tǒng)基于不同的網(wǎng)絡、操作系統(tǒng)、計算機硬件和編程語言,因此必須考慮采用一種通用的網(wǎng)絡通信協(xié)議來屏蔽異構(gòu)系統(tǒng)之間的差異。開發(fā)人員一般選擇中間件來屏蔽這些差異。
◎透明性:分布式系統(tǒng)中任意組件的故障及主機的升級或遷移,對用戶來說都是透明的。
◎并發(fā)性:應用分布式系統(tǒng)的目的是更好地共享資源,所以系統(tǒng)中的每個資源在并發(fā)環(huán)境下都必須是安全的。
◎可擴展性:隨著業(yè)務量的增加,系統(tǒng)必須具備可擴展性,以應對因業(yè)務量增長而增加的外部流量。
◎故障獨立性:任何計算機都有可能發(fā)生故障,而且各計算機發(fā)生的故障類型不盡相同,發(fā)生故障的時間也各不相同。所以,分布式系統(tǒng)一般允許發(fā)生部分故障,而不影響整個系統(tǒng)的正常使用。
◎數(shù)據(jù)一致性:因為數(shù)據(jù)被分散或者復制到不同的機器上,所以需要保證各臺服務器之間數(shù)據(jù)的一致性。
◎負載均衡:由于分布式系統(tǒng)是多機協(xié)同工作的系統(tǒng),因此為了提高系統(tǒng)的整體效率和吞吐量,必須考慮最大化地發(fā)揮每個節(jié)點的作用,以最大化地利用資源,避免某個節(jié)點過載或者浪費資源。
4.分布式系統(tǒng)的衡量指標
◎系統(tǒng)的性能:系統(tǒng)每秒的事務處理能力,通常用TPS(Transactions Per Second)來衡量。
◎系統(tǒng)的可用性:系統(tǒng)在面對各種異常時可以正確提供服務的能力。該指標可以用系統(tǒng)停服的時間與正常服務時間的比例來衡量,也可以用某功能的失敗次數(shù)與成功次數(shù)的比例來衡量。系統(tǒng)的可用性是分布式系統(tǒng)的重要指標,是系統(tǒng)容錯能力的體現(xiàn)。
◎系統(tǒng)的可擴展性:分布式系統(tǒng)通過擴展集群的機器規(guī)模來提高系統(tǒng)性能(增大接口吞吐量、降低接口延時、增大接口并發(fā)量)、存儲容量、計算能力的特性。
RPC(Remote Procedure Call,遠程過程調(diào)用)是一種進程間通信方式,也是一種技術(shù)思想。使用 RPC 技術(shù)時,允許本地程序通過網(wǎng)絡調(diào)用另一臺服務器上的函數(shù)或者方法,具體調(diào)用過程一般由 RPC 框架實現(xiàn),不用編碼實現(xiàn)。即無論是調(diào)用本地函數(shù)還是調(diào)用遠程函數(shù),我們編寫的調(diào)用代碼在本質(zhì)上基本相同。
1.RPC框架的工作原理
RPC框架要向服務調(diào)用方和服務提供方屏蔽各類復雜性操作,比如負載均衡、序列化和反序列化、網(wǎng)絡重試、超時等,主要由客戶端、服務器端和注冊中心3種角色構(gòu)成,整體架構(gòu)如圖3-1所示。

◎客戶端(Client):調(diào)用遠程服務的服務消費方。客戶端調(diào)用遠程服務就像調(diào)用本地函數(shù)一樣,客戶端負責序列化、反序列化、連接池管理、負載均衡、故障轉(zhuǎn)移、超時管理、異步管理等。
◎服務器端(Server):暴露服務的服務提供方。服務器端如同實現(xiàn)一個本地函數(shù)一樣來實現(xiàn)遠程服務提供,服務器端需要做收發(fā)包隊列、I/O線程、工作線程、序列化及反序列化等工作。
◎注冊中心:服務注冊與發(fā)現(xiàn)的注冊中心。
2.RPC調(diào)用說明
一次RPC調(diào)用流程主要由5部分組成,分別是客戶端、客戶端存根、服務器端存根、服務提供端和網(wǎng)絡傳輸,其調(diào)用流程如圖3-2所示。
◎客戶端:服務調(diào)用方。
◎客戶端存根:用于存放服務器端的地址信息,將客戶端的請求參數(shù)等信息打包成網(wǎng)絡消息,再通過網(wǎng)絡傳輸發(fā)送給服務器端。
◎服務器端存根:接收客戶端發(fā)送過來的請求消息并解包,然后調(diào)用本地服務處理。
◎服務提供端:服務的真正提供者。
◎網(wǎng)絡傳輸:底層數(shù)據(jù)傳輸,可以是TCP或HTTP。

業(yè)務在剛開始時都是單體應用,隨著用戶量和訪問量的增加,在架構(gòu)層面會發(fā)生變化,逐步由單體應用開發(fā)轉(zhuǎn)為分布式應用開發(fā),比如把單體應用中的每個模塊都按照特定的方法拆分成一組獨立的服務,服務與服務之間通過HTTP或者RPC方式調(diào)用。隨著業(yè)務量的逐步增加,服務的數(shù)量也逐步增加。這時維護服務的URL地址就變得非常麻煩,所以需要設(shè)計一套系統(tǒng)來統(tǒng)一管理每個服務所對應的URL地址。這套系統(tǒng)就叫作注冊中心。當有多個服務時,消費者需要根據(jù)規(guī)則來調(diào)用相關(guān)服務,實現(xiàn)軟負載均衡,以達到資源利用率最大化的目的。因此,服務注冊、服務發(fā)現(xiàn)、負載均衡、流量削峰、版本兼容、服務熔斷、服務降級、服務限流等方面的問題,都是因服務拆分所引發(fā)的一系列問題。如何解決這些問題,讓服務更穩(wěn)定地運行,就叫作服務治理。
總體來說,服務治理指的是企業(yè)為了確保事情順利完成而實施的內(nèi)容,包括最佳實踐、架構(gòu)原則、治理規(guī)程、規(guī)律及其他決定性的因素。下面針對服務治理過程中的各個環(huán)節(jié)做相關(guān)說明。
(1)服務:它是分布式架構(gòu)下的基礎(chǔ)單元,包括一個或一組軟件功能,其目的是不同的客戶端通過網(wǎng)絡獲取相應的數(shù)據(jù),而不用關(guān)注底層實現(xiàn)的具體細節(jié)。以用戶服務為例,當客戶端調(diào)用用戶服務的注冊功能時,注冊信息會被寫入數(shù)據(jù)庫、緩存并發(fā)送消息來通知其他關(guān)注注冊事件的系統(tǒng),但是調(diào)用方并不清楚服務的具體處理邏輯。
(2)注冊中心:它是微服務架構(gòu)中的“通訊錄”,記錄了服務和服務地址的映射關(guān)系,主要涉及服務的提供者、服務注冊中心和服務的消費者。在數(shù)據(jù)流程中,服務提供者在啟動服務之后將服務注冊到注冊中心;服務消費者(或稱為服務消費方)在啟動時,會從注冊中心拉取相關(guān)配置,并將其放到緩存中。注冊中心的優(yōu)勢在于解耦了服務提供者和服務消費者之間的關(guān)系,并且支持彈性擴容和縮容。當服務需要擴容時,只需要再部署一個該服務。當服務成功啟動后,會自動被注冊到注冊中心,并推送給消費者。
(3)服務注冊與發(fā)布:服務實例在啟動時被加載到容器中,并將服務自身的相關(guān)信息,比如接口名稱、接口版本、IP地址、端口等注冊到注冊中心,并使用心跳機制定期刷新當前服務在注冊中心的狀態(tài),以確認服務狀態(tài)正常,在服務終止時將其從注冊表中刪除。服務注冊包括自注冊模式和第三方注冊模式這兩種模式。
◎自注冊模式:服務實例負責在服務注冊表中注冊和注銷服務實例,同時服務實例要發(fā)送心跳來保證注冊信息不過期。其優(yōu)點是,相對簡單,無須其他系統(tǒng)功能的支持;缺點是,需要把服務實例和服務注冊表聯(lián)系起來,必須在每種編程語言和框架內(nèi)部實現(xiàn)注冊代碼。
◎第三方注冊模式:服務實例由另一個類似的服務管理器負責注冊,服務管理器通過查詢部署環(huán)境或訂閱事件來跟蹤運行服務的改變。當管理器發(fā)現(xiàn)一個新的可用服務時,會向注冊表注冊此服務,同時服務管理器負責注銷終止的服務實例。第三方注冊模式的主要優(yōu)勢是服務與服務注冊表是分離的,無須為每種編程語言和架構(gòu)都完成服務注冊邏輯。相應地,服務實例是通過一個集中化管理的服務進行管理的;缺點是,需要一個高可用系統(tǒng)來支撐。
(4)服務發(fā)現(xiàn):使用一個注冊中心來記錄分布式系統(tǒng)中全部服務的信息,以便其他服務快速找到這些已注冊的服務。其目前有客戶端發(fā)現(xiàn)模式和服務器端發(fā)現(xiàn)模式這兩種模式。
◎客戶端發(fā)現(xiàn)模式:客戶端從服務注冊服務中查詢所有可用服務實例的地址,使用負載均衡算法從多個服務實例中選擇一個,然后發(fā)出請求。其優(yōu)勢在于客戶端知道可用服務注冊表的信息,因此可以定義多種負載均衡算法,而且負載均衡的壓力都集中在客戶端。
◎服務器端發(fā)現(xiàn)模式:客戶端通過負載均衡器向某個服務提出請求,負載均衡器從服務注冊服務中查詢所有可用服務實例的地址,將每個請求都轉(zhuǎn)發(fā)到可用的服務實例中。與客戶端發(fā)現(xiàn)一樣,服務實例在服務注冊表中注冊或者注銷。我們可以將HTTP服務、Nginx的負載均衡器都理解為服務器端發(fā)現(xiàn)模式。其優(yōu)點是,客戶端無須關(guān)注發(fā)現(xiàn)的細節(jié),可以減少客戶端框架需要完成的服務發(fā)現(xiàn)邏輯;客戶端只需簡單地向負載均衡器發(fā)送請求。其缺點是,在服務器端需要配置一個高可用的負載均衡器。
(5)流量削峰:使用一些技術(shù)手段來削弱瞬時的請求高峰,讓系統(tǒng)吞吐量在高峰請求下可控,也可用于消除毛刺,使服務器資源的利用更加均衡、充分。常見的削峰策略有隊列、限頻、分層過濾、多級緩存等。
(6)版本兼容:在升級版本的過程中,需要考慮升級版本后新的數(shù)據(jù)結(jié)構(gòu)能否理解和解析舊的數(shù)據(jù),新協(xié)議能否理解舊的協(xié)議并做出預期內(nèi)合適的處理。這就需要在服務設(shè)計過程中做好版本兼容工作。
(7)服務熔斷:其作用類似于家用的保險絲。當某服務出現(xiàn)不可用或響應超時的情況時,已經(jīng)達到系統(tǒng)設(shè)定的閾值,為了防止整個系統(tǒng)出現(xiàn)雪崩,會暫時停止對該服務的調(diào)用。
(8)服務降級:在服務器壓力劇增的情況下,根據(jù)當前業(yè)務情況及流量對一些服務和頁面有策略性地降級,以此釋放服務器資源,保證核心任務的正常運行。降級時往往會指定不同的級別,面對不同的異常等級執(zhí)行不同的處理。
(9)服務限流:服務限流可以被認為是服務降級的一種。它通過限制系統(tǒng)的輸入和輸出流量來達到保護系統(tǒng)的目的。一般來說,系統(tǒng)的吞吐量是可以被測算的。為了保證系統(tǒng)的穩(wěn)定運行,一旦達到閾值,就需要限制流量。限制措施有延遲處理、拒絕處理或者部分拒絕處理等。
(10)負載均衡策略:它是用于解決一臺機器無法處理所有請求而產(chǎn)生的一種算法。當集群里的1臺或者多臺服務器不能響應請求時,負載均衡策略會通過合理分攤流量,讓更多的服務器均衡處理流量請求,不會因某一高峰時刻流量大而導致單個服務器的 CPU或內(nèi)存急劇上升。
本文節(jié)選自《架構(gòu)演變實戰(zhàn):從單體到微服務再到中臺》這本書

大家可以掃描上方二維碼購買,書中通過真實案例實戰(zhàn)的方式完整地講述了如何從一個單體架構(gòu)逐步轉(zhuǎn)型到中臺的歷程!強烈推薦給大家!是很好的架構(gòu)師參考工具書,也是技術(shù)優(yōu)化的參考書。
福利時刻
本次福利將送出《架構(gòu)演變實戰(zhàn):從單體到微服務再到中臺》* 5本
您只需要點擊下方卡片,關(guān)注公眾號,并發(fā)送關(guān)鍵詞:20220726 即可參數(shù)抽獎。
