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

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 服務、子服務、服務的部署」


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

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 框架的服務拆分。


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


  • 左邊:單純的進行了服務拆分,形成了4個互獨立的服務。這裏其實就出現了兩個問題:客戶端需要關心我請求的 api 到底是屬於哪個服務的,然後再往相應的服務端發送請求;雖然服務做了拆分,但是如果其中一個服務出現問題掛掉了,那麼整個架構中的服務都不可用。

  • 右邊:將這4個子服務作爲一個服務的集合,並簡單地應用了 SOA 架構。可以看到除了四個子服務之外,最上層還多了一個 gateway,而最下層也多了三個底層模塊。最下層的三個底層模塊很好理解,有一些工作是每個子服務都需要做的,比如版本控制、性能監控等,底層就是抽出了這樣的公共模塊以便子服務複用。最上層的 gateway,網關,顧名思義,你們如果想訪問我管理的這些子服務,直接訪問我就好了;也就是說客戶端只需要向 gateway 發送請求,gateway 會根據所配置的規則將請求轉發到正確的子服務上,這也就解決了上文所述左邊的設計中遇到的兩個問題。


子服務及子服務的部署

1. 服務的實現

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

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


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


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

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

  • 節點:每個節點都是等同的,每個節點上都運行着相同的服務,等待處理負載均衡器轉發過來的請求。節點可以是一個物理機、虛擬機、也可以是一個 docker 容器。


2. 服務的部署

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

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

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

1)滾動部署

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

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

首先更新第一個節點。

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


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

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


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

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


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

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


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

2)藍綠部署

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

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

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


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

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


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

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


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

3)灰度發佈

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

首先更新一個節點。

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


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

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


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

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


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

“我們相信人人都可以成爲一個java開發大神,現在開始,找個師兄,帶你入門,學習的路上不再迷茫。這裏是java開發修真院,初學者轉行到互聯網行業的聚集地。"

我做開發十多年的時間,如果大家對於學習java的學習方法,學習路線以及你不知道自己應該是自學還是培訓的疑問,都可以隨時來問我,大家可以加我的java交流學習qun:615741636。qun內有學習教程以及開發工具。

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