1. 程式人生 > 實用技巧 >10-Dubbo框架裡的微服務元件

10-Dubbo框架裡的微服務元件

經過前面幾期的講解,你應該已經對微服務的架構有了初步的瞭解。簡單回顧一下,微服務的架構主要包括服務描述、服務發現、服務呼叫、服務監控、服務追蹤以及服務治理這幾個基本元件。

那麼每個基本元件從架構和程式碼設計上該如何實現?元件之間又是如何串聯來實現一個完整的微服務架構呢?今天我就以開源微服務框架Dubbo為例來給你具體講解這些元件。

服務釋出與引用

專欄前面我講過服務釋出與引用的三種常用方式:RESTful API、XML配置以及IDL檔案,其中Dubbo框架主要是使用XML配置方式,接下來我通過具體例項,來給你講講Dubbo框架服務釋出與引用是如何實現的。

首先來看服務釋出的過程,下面這段程式碼是服務提供者的XML配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
 
    <!-- 提供方應用資訊,用於計算依賴關係 -->
    <dubbo:application name="hello-world-app"  />
 
    <!-- 使用multicast廣播註冊中心暴露服務地址 -->
    <dubbo:registry address="multicast://224.5.6.7:1234" />
 
    <!-- 用dubbo協議在20880埠暴露服務 -->
    <dubbo:protocol name="dubbo" port="20880" />
 
    <!-- 宣告需要暴露的服務介面 -->
    <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" />
 
    <!-- 和本地bean一樣實現服務 -->
    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />
</beans>

其中“dubbo:service”開頭的配置項聲明瞭服務提供者要釋出的介面,“dubbo:protocol”開頭的配置項聲明瞭服務提供者要釋出的介面的協議以及埠號。

Dubbo會把以上配置項解析成下面的URL格式:

dubbo://host-ip:20880/com.alibaba.dubbo.demo.DemoService

然後基於擴充套件點自適應機制,通過URL的“dubbo://”協議頭識別,就會呼叫DubboProtocol的export()方法,開啟服務埠20880,就可以把服務demoService暴露到20880埠了。

再來看下服務引用的過程,下面這段程式碼是服務消費者的XML配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
 
    <!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣 -->
    <dubbo:application name="consumer-of-helloworld-app"  />
 
    <!-- 使用multicast廣播註冊中心暴露發現服務地址 -->
    <dubbo:registry address="multicast://224.5.6.7:1234" />
 
    <!-- 生成遠端服務代理,可以和本地bean一樣使用demoService -->
    <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" />
</beans>

其中“dubbo:reference”開頭的配置項聲明瞭服務消費者要引用的服務,Dubbo會把以上配置項解析成下面的URL格式:

dubbo://com.alibaba.dubbo.demo.DemoService

然後基於擴充套件點自適應機制,通過URL的“dubbo://”協議頭識別,就會呼叫DubboProtocol的refer()方法,得到服務demoService引用,完成服務引用過程。

服務註冊與發現

先來看下服務提供者註冊服務的過程,繼續以前面服務提供者的XML配置為例,其中“dubbo://registry”開頭的配置項聲明瞭註冊中心的地址,Dubbo會把以上配置項解析成下面的URL格式:

registry://multicast://224.5.6.7:1234/com.alibaba.dubbo.registry.RegistryService?export=URL.encode("dubbo://host-ip:20880/com.alibaba.dubbo.demo.DemoService")

然後基於擴充套件點自適應機制,通過URL的“registry://”協議頭識別,就會呼叫RegistryProtocol的export()方法,將export引數中的提供者URL,註冊到註冊中心。

再來看下服務消費者發現服務的過程,同樣以前面服務消費者的XML配置為例,其中“dubbo://registry”開頭的配置項聲明瞭註冊中心的地址,跟服務註冊的原理類似,Dubbo也會把以上配置項解析成下面的URL格式:

registry://multicast://224.5.6.7:1234/com.alibaba.dubbo.registry.RegistryService?refer=URL.encode("consummer://host-ip/com.alibaba.dubbo.demo.DemoService")

然後基於擴充套件點自適應機制,通過URL的“registry://”協議頭識別,就會呼叫RegistryProtocol的refer()方法,基於refer引數中的條件,查詢服務demoService的地址。

服務呼叫

專欄前面我講過在服務呼叫的過程中,通常把服務消費者叫作客戶端,服務提供者叫作服務端,發起一次服務呼叫需要解決四個問題:

  • 客戶端和服務端如何建立網路連線?

  • 服務端如何處理請求?

  • 資料傳輸採用什麼協議?

  • 資料該如何序列化和反序列化?

其中前兩個問題客戶端和服務端如何建立連線和服務端如何處理請求是通訊框架要解決的問題,Dubbo支援多種通訊框架,比如Netty 4,需要在服務端和客戶端的XML配置中新增下面的配置項。

服務端:

<dubbo:protocol server="netty4" />

客戶端:

<dubbo:consumer client="netty4" />

這樣基於擴充套件點自適應機制,客戶端和服務端之間的呼叫會通過Netty 4框架來建立連線,並且服務端採用NIO方式來處理客戶端的請求。

再來看下Dubbo的資料傳輸採用什麼協議。Dubbo不僅支援私有的Dubbo協議,還支援其他協議比如Hessian、RMI、HTTP、Web Service、Thrift等。下面這張圖描述了私有Dubbo協議的協議頭約定。


(圖片來源:https://dubbo.incubator.apache.org/docs/zh-cn/dev/sources/images/dubbo_protocol_header.jpg

至於資料序列化和反序列方面,Dubbo同樣也支援多種序列化格式,比如Dubbo、Hession 2.0、JSON、Java、Kryo以及FST等,可以通過在XML配置中新增下面的配置項。

例如:

<dubbo:protocol name="dubbo" serialization="kryo"/>

服務監控

服務監控主要包括四個流程:資料採集、資料傳輸、資料處理和資料展示,其中服務框架的作用是進行埋點資料採集,然後上報給監控系統。

在Dubbo框架中,無論是服務提供者還是服務消費者,在執行服務呼叫的時候,都會經過Filter呼叫鏈攔截,來完成一些特定功能,比如監控資料埋點就是通過在Filter呼叫鏈上裝備了MonitorFilter來實現的,詳細的程式碼實現你可以參考這裡

服務治理

服務治理手段包括節點管理、負載均衡、服務路由、服務容錯等,下面這張圖給出了Dubbo框架服務治理的具體實現。


(圖片來源:http://dubbo.incubator.apache.org/docs/zh-cn/user/sources/images/cluster.jpg

圖中的Invoker是對服務提供者節點的抽象,Invoker封裝了服務提供者的地址以及介面資訊。

  • 節點管理:Directory負責從註冊中心獲取服務節點列表,並封裝成多個Invoker,可以把它看成“List<Invoker>” ,它的值可能是動態變化的,比如註冊中心推送變更時需要更新。

  • 負載均衡:LoadBalance負責從多個Invoker中選出某一個用於發起呼叫,選擇時可以採用多種負載均衡演算法,比如Random、RoundRobin、LeastActive等。

  • 服務路由:Router負責從多個Invoker中按路由規則選出子集,比如讀寫分離、機房隔離等。

  • 服務容錯:Cluster將Directory中的多個Invoker偽裝成一個Invoker,對上層透明,偽裝過程包含了容錯邏輯,比如採用Failover策略的話,呼叫失敗後,會選擇另一個Invoker,重試請求。

一次服務呼叫的流程

上面我講的是Dubbo下每個基本元件的實現方式,那麼Dubbo框架下,一次服務呼叫的流程是什麼樣的呢?下面結合這張圖,我來給你詳細講解一下。


(圖片來源:https://dubbo.incubator.apache.org/docs/zh-cn/dev/sources/images/dubbo-extension.jpg

首先我來解釋微服務架構中各個元件分別對應到上面這張圖中是如何實現。

  • 服務釋出與引用:對應實現是圖裡的Proxy服務代理層,Proxy根據客戶端和服務端的介面描述,生成介面對應的客戶端和服務端的Stub,使得客戶端呼叫服務端就像本地呼叫一樣。

  • 服務註冊與發現:對應實現是圖裡的Registry註冊中心層,Registry根據客戶端和服務端的介面描述,解析成服務的URL格式,然後呼叫註冊中心的API,完成服務的註冊和發現。

  • 服務呼叫:對應實現是Protocol遠端呼叫層,Protocol把客戶端的本地請求轉換成RPC請求。然後通過Transporter層來實現通訊,Codec層來實現協議封裝,Serialization層來實現資料序列化和反序列化。

  • 服務監控:對應實現層是Filter呼叫鏈層,通過在Filter呼叫鏈層中加入MonitorFilter,實現對每一次呼叫的攔截,在呼叫前後進行埋點資料採集,上傳給監控系統。

  • 服務治理:對應實現層是Cluster層,負責服務節點管理、負載均衡、服務路由以及服務容錯。

再來看下微服務架構各個元件是如何串聯起來組成一個完整的微服務框架的,以Dubbo框架下一次服務呼叫的過程為例,先來看下客戶端發起呼叫的過程。

  • 首先根據介面定義,通過Proxy層封裝好的透明化介面代理,發起呼叫。

  • 然後在通過Registry層封裝好的服務發現功能,獲取所有可用的服務提供者節點列表。

  • 再根據Cluster層的負載均衡演算法從可用的服務節點列表中選取一個節點發起服務呼叫,如果呼叫失敗,根據Cluster層提供的服務容錯手段進行處理。

  • 同時通過Filter層攔截呼叫,實現客戶端的監控統計。

  • 最後在Protocol層,封裝成Dubbo RPC請求,發給服務端節點。

這樣的話,客戶端的請求就從一個本地呼叫轉化成一個遠端RPC呼叫,經過服務呼叫框架的處理,通過網路傳輸到達服務端。其中服務呼叫框架包括通訊協框架Transporter、通訊協議Codec、序列化Serialization三層處理。

服務端從網路中接收到請求後的處理過程是這樣的:

  • 首先在Protocol層,把網路上的請求解析成Dubbo RPC請求。

  • 然後通過Filter攔截呼叫,實現服務端的監控統計。

  • 最後通過Proxy層的處理,把Dubbo RPC請求轉化為介面的具體實現,執行呼叫。

總結

今天我給你講述了Dubbo服務化框架每個基本元件的實現方式,以及一次Dubbo呼叫的流程。

對於學習微服務架構來說,最好的方式是去實際搭建一個微服務的框架,甚至去從程式碼入手做一些二次開發

你可以按照Dubbo的官方文件去安裝並搭建一個服務化框架。如果想深入瞭解它的實現的話,可以下載原始碼來閱讀。