歡迎光臨
每天分享高質量文章

不是後端也應該知道的「 web 服務、子服務、服務的部署」

(給ImportNew加星標,提高Java技能)

 

鏈接:webfe.kujiale.com/draft-fu-wu-bu-shu-fen-xiang/

 

web 服務是什麼

 

1. 定義

 

我們先來看一個很通俗的定義,來自於wiki。

 

Web service 指的是,一個平臺通過 web 向其它平臺來提供服務。

 

更專業一點的定義怎麼說呢?我們來看一下 W3C 對 web service 的定義。

 

Web service 是一個軟體系統,使得不同機器可以在網絡間進行互動操作。

 

2. 要素

 

想要實現一個平臺在網絡間呼叫另一個平臺的服務,至少需要明確三點:

 

  • 如何將平臺上的代碼作為服務暴露出去供其它平臺呼叫;
  • 使用什麼樣的網絡協議通信;
  • 使用什麼樣的格式作為通信內容。

 

從 WSDL 理解 web service 的要素

 

要回答以上問題,我們可以先簡單的瞭解一下什麼是 WSDL,Web Services Description Language,網絡服務描述語言。我們知道服務的提供方其實本質上是由代碼編寫而成,而服務的呼叫方通過發起一個網絡請求來呼叫服務。那麼通俗的說,WSDL 做的事情就是,描述瞭如何根據呼叫方發送的網絡請求,找到服務提供方,進而找到要運行哪一段代碼,從而得到結果傳回給呼叫方。

 

WSDL 是基於 XML 格式的文件,包括兩部分,抽象定義和具體定義。

 

WSDL的抽象定義

 

WSDL 的抽象定義,獨立於提供服務的平臺和服務實現的語言,定義了該服務通過什麼樣的網絡協議、使用什麼樣的訊息格式與呼叫方通信。網絡協議是不受限制的,可以是 http、ftp、smtp 等其它網絡傳輸協議,不過大部分情況下我們使用的是 http 協議。訊息格式也是多種多樣的,最初唯一被廣泛使用的訊息格式是基於 XML 格式的 SOAP,簡單物件訪問協議,後來 REST 流行了起來,出現了基於 REST + XML 的訊息格式,再後來發展為 REST + JSON 的訊息格式,也就是我們現在應用最廣泛的一種。

 

WSDL 的具體定義

 

WSDL 的具體定義,與平臺和語言相關,定義了一個具體的服務呼叫,請求引數和傳回引數是怎麼樣的、以及通過哪一部分代碼的運行可以得到結果等等。

 

咖啡館的類比

 

我們使用一個咖啡館來類比 WSDL 的工作原理,咖啡館是服務提供方,提供了下單、取餐、付款等服務,咖啡館的員工手冊則相當於提供服務的代碼,顧客是服務呼叫方。WSDL 的抽象定義,定義了顧客如何找到咖啡館的位置,以及顧客和咖啡館的員工使用哪國語言進行交流等等;而 WSDL 的具體定義,則定義了每一個具體的服務,如下單服務,顧客需要提供什麼,工作人員在員工手冊的哪一頁可以找到下單的操作流程,以及工作人員會傳回什麼給顧客,等等。

 

WSDL 文件可以由服務的實現代碼自動生成,反之也可以通過定義好的 WSDL 文件生成代碼框架。

 

3. 應用方式

 

最常見的兩種 web service 的組織形式是:RPC 遠程過程呼叫,REST 表述性狀態轉移。從本質上來說,兩者定義的都是規範,一個是面向過程的遠程呼叫規範,一個是面向資源的遠程呼叫規範。

 

RPC 遠程過程呼叫

 

RPC,Remote Procedure Call,遠程過程呼叫,定義了平臺與平臺之間面向過程進行服務呼叫的規範。它的本質思想是,將一個平臺上的多個函式過程,作為一個服務,提供給另一個平臺呼叫。所以以 RPC 為規範的服務,需要關心的是「我要做一件什麼事」。RPC 規範是協議無關的,可以使用各種網絡協議實現。

 

REST 表述性狀態傳遞

 

那麼 REST 又是什麼?不知道 REST 沒關係,如果你接觸過 GET、POST、PUT、DELETE 這樣的請求,不要懷疑,這種我們通常意義上所說的 http 請求大部分都是基於 REST 規範而來的。基於 REST 規範設計的 api 也稱之為是 RESTful 的 api,這樣的 api 的主題必須是資源,它關心的是「我要對某個資源進行什麼樣的操作」。為什麼 REST 可以流行起來呢?這就跟我們為什麼要用面向物件的思想進行編程是一個道理,萬物皆物件,外物皆資源。這裡推薦一篇非常通俗的講解 REST 規範的文章 如何給老婆解釋什麼是RESTful。

 

RPC 與 REST 的比較

 

總的來說,PRC 與網絡協議無關,關心的是過程;REST 基於 http 協議,關心的是資源。下圖演示了針對相同的有關用戶的操作,REST 形式的服務(左邊)和 RPC 形式的服務(右邊)設計上的區別。

 

 

那麼在具體的使用場景下,對於兩種設計規範,我們應該如何選擇呢?我覺得二者的取捨,可以類比於函式式編程與面向物件的編程,各自有各自適合的場景,甚至在某些場景下,使用二者皆可且各有利弊。重要的是要理解這兩個設計規範的本質和初衷,並根據實際場景和個人的使用習慣最初抉擇。

 

web service 與子服務

 

在談子服務之前,我們來繼續之前咖啡館的假設,從而理解什麼是子服務以及我們為什麼需要子服務。

 

為什麼我們需要子服務

 

設想一個咖啡館的正常運作,需要以下職能人員的參與。

 

  • 前臺:負責創建、修改、刪除客戶的訂單
  • 收銀員:收取訂單相應的費用、找零、管理咖啡館的日常支出
  • 服務生:為客戶配送咖啡到相應的座位上,回收餐具
  • 清潔工:維護店內清潔、桌椅擺放、空調燈光等硬體設施
  • 經理:保證店鋪正常運行,解決問題和異常情況

 

對於這些職能人員來說,核心要素有三點:

 

  1. 他們所做的工作有明確的界限劃分;
  2. 他們互相之間可能需要進行交流;
  3. 他們共同維護了咖啡館的運作。

 

為什麼咖啡館不是由一個非常厲害的全能的人承擔所有的工作呢?這個很容易理解:

 

  • 首先厲害的人比普通人更加難找到;
  • 而且要同時兼顧這麼多的工作內容是更加容易出錯的;
  • 還有最重要的一點是,如果他生病了,整個店就完全沒有辦法運作下去。

 

那麼將咖啡館的例子映射到 web 服務上,提供一個單一的 web 服務來支持整個咖啡館的運作自然也是不合理的:

 

  • 想要維護好一個大型的系統比維護好一個小型的系統更加困難;
  • 業務邏輯冗雜的系統更容易出錯;
  • 如果這個系統的一小塊內容出現問題很容易導致整個系統的崩盤。

 

那麼如何拆分一個服務系統呢,答案就是子服務了。我們將整個系統根據職能的劃分拆分成5個子服務,分別對應到上文的5種職能人員。

 

  • 訂單管理服務
  • 賬戶管理服務
  • 餐具管理服務
  • 店內環境管理服務
  • 性能監控與異常處理服務

 

同樣的這些子服務的核心要素如下:

 

  • 這5個子服務所提供的接口有明確的界限劃分;
  • 子服務之間可以互相呼叫;
  • 共同保證了整個咖啡館的運作。

 

理解了子服務的概念以及 web service 為什麼需要子服務之後,新的問題出現了:子服務如何進行合理的拆分?如何管理多個子服務?子服務間如何通信?

 

這裡就不得不提到 SOA 了。

 

通過 SOA 架構組織子服務

 

SOA,Service Oriented Architecture,是一個面向服務的架構設計,通俗的說它也是一個規範,定義瞭如何管理服務的集合及他們之間的通訊方式。它本質上和 web service 以及子服務都沒有絕對的依賴關係,它甚至比 web service 出現的更加早。然而人們在 web service 上發現了它的用武之地,也就是說 SOA 剛好可以在 web service 的管理上體現它的價值。於是乎,造成了幾乎所有 SOA 的應用場景都與 web service 相關這樣的現狀,也導致了這兩個概念一定程度上發生了混淆。

 

既然 SOA 框架是對服務的集合的管理,那麼它究竟比單純的服務拆分多做了哪些事情呢?

 

我們來看一下下圖這個簡單的例子。假設我們要將整個系統拆分成4個子服務:ACCOUNT、C2D、ASK、DESIGN。左邊為單純的服務拆分,右邊為基於 SOA 框架的服務拆分。

 

 

  • 左邊:單純的進行了服務拆分,形成了4個互獨立的服務。這裡其實就出現了兩個問題:客戶端需要關心我請求的 api 到底是屬於哪個服務的,然後再往相應的服務端發送請求;雖然服務做了拆分,但是如果其中一個服務出現問題掛掉了,那麼整個架構中的服務都不可用。
  • 右邊:將這4個子服務作為一個服務的集合,並簡單地應用了 SOA 架構。可以看到除了四個子服務之外,最上層還多了一個 gateway,而最下層也多了三個底層模塊。最下層的三個底層模塊很好理解,有一些工作是每個子服務都需要做的,比如版本控制、性能監控等,底層就是抽出了這樣的公共模塊以便子服務復用。最上層的 gateway,網關,顧名思義,你們如果想訪問我管理的這些子服務,直接訪問我就好了;也就是說客戶端只需要向 gateway 發送請求,gateway 會根據所配置的規則將請求轉發到正確的子服務上,這也就解決了上文所述左邊的設計中遇到的兩個問題。

 

子服務及子服務的部署

 

1. 服務的實現

 

web 服務是一個軟體系統,軟體系統是通過代碼形成的。那麼這樣一個軟體系統是如何從一大坨代碼轉化為穩定的、可訪問的、可更新的服務的呢?

一個有一定流量的服務一般是由類似這樣的結構組成的。

 

 

上層是一個負載均衡器(load balancer),下層是多個相同的節點(node)。

 

  • 負載均衡器:將針對這個服務的請求,合理的分發到下麵的某一個節點上,以儘量達到這樣的目的:請求盡可能的被完成(例如其中一個節點沒有正常運行不會導致請求失敗)、每個節點承擔均勻的壓力(例如同時有一萬個請求,不至於扎堆到同一個節點上去導致節點出現性能問題)。負責均衡器可以通過網絡設備、虛擬 ip、nginx 反向代理、甚至僅僅是一段代碼來實現。
  • 節點:每個節點都是等同的,每個節點上都運行著相同的服務,等待處理負載均衡器轉發過來的請求。節點可以是一個物理機、虛擬機、也可以是一個 docker 容器。

 

2. 服務的部署

 

服務的部署,簡單來說就是將該服務的軟體系統的最新代碼克隆到每一個節點上,再在每一個節點上將服務運行起來。那麼服務的更新無非就是重新對每一個節點進行一次部署。

 

但是不要忘記,在一個節點上重新運行服務會導致該節點的服務有一個短暫的罷工,那麼如何保證在完成對服務的更新的同時,保證對於客戶端來說服務不會出現掛掉的狀態?這時候就需要一定的部署策略。

 

註:下圖中綠色節點均表示未更新節點,藍色節點均表示已更新節點

 

1)滾動部署

 

滾動部署,每次只更新 n 個節點,等待前 n 個節點部署好了,再更新下 n 個節點,這樣可以保證同一時間只可能最多有 n 個節點處在不可用狀態。

下麵四張圖是一個滾動部署過程的例子,例子中 n 為 1。

首先更新第一個節點。

 

 

待第一個節點更新完畢之後,更新第二個節點。

 

 

待第二個節點更新完畢之後,更新第三個節點。

 

 

待第三個節點更新完畢之後,更新第四個節點。全部的節點都完成了更新。

 

 

滾動部署的缺點是,在部署過程中,客戶端可以同時訪問到更新前的服務和更新後的服務。

 

2)藍綠部署

 

藍綠部署,如下麵三張圖所示,分為三個步驟。

 

首先新增四個節點,並將新版的服務部署上去。

 

 

全部部署好之後將負載均衡器指向新的四個節點。

 

 

移除原有的舊版本服務的四個節點。

 

 

藍綠部署解決了滾動部署會同時出現新舊服務並存的缺點,但是對資源的要求更高。

 

3)灰度發佈

 

灰度發佈是平滑過渡的一種發佈方式。讓一部分用戶繼續用舊版本的服務,一部分用戶開始體驗新版本的服務,如果用戶對新版本沒有什麼反對意見,那麼逐步擴大範圍,將所有的舊版本服務更新為新版本服務。灰度發佈可以保證整體系統的穩定,在初始灰度的時候就可以發現、調整問題,以避免產生無法輓回的影響。灰度發佈的實現如下麵三張圖所示。

 

首先更新一個節點。

 

 

然後通過負載均衡器按照一定的規則篩選出 20% 的用戶(比如用戶 id 除以 5 餘 0),並將這 20% 的用戶所發出的全部請求都轉發到已經更新過的節點。

 

 

再更新第二個節點,並將包含之前那 20% 的用戶的 50% 的用戶的請求轉發到兩個更新過的節點上去。

 

 

以此類推直到所有節點更新完畢,100% 的用戶的請求都會請求到新的服務。這裡需要註意的是,灰發的用戶百分比最好和更新節點的占比相近,這樣可以保證每個節點可以承受相似的壓力。如果只更新了一個節點,而轉發了 90% 的用戶的請求到新服務上,那麼這個節點很可能會出現性能問題。

    赞(0)

    分享創造快樂