1. 程式人生 > >圖解Dubbo和ZooKeeper是如何協同工作的?

圖解Dubbo和ZooKeeper是如何協同工作的?

介紹

GitHub地址:https://github.com/erlieStar/study-dubbo

微服務是最近比較火的概念,而微服務框架目前主流的有Dubbo和Spring Cloud,兩者都是為了解決微服務遇到的各種問題而產生的,即遇到的問題是一樣的,但是解決的策略卻有所不同,所以這2個框架經常拿來比較。沒用過Dubbo的小夥伴也不用擔心,其實Dubbo還是比較簡單的,看完本文你也能掌握一個大概,重要的不是程式碼,而是思想。

Dubbo實現服務呼叫是通過RPC的方式,即客戶端和服務端共用一個介面,客戶端面向介面寫呼叫,服務端面向介面寫實現,中間的網路通訊交給框架去實現,想深入瞭解的看推薦閱讀。

使用入門

服務提供者

定義服務介面

public interface DemoService {
    String sayHello(String name);
}

在服務提供方實現介面

public class DemoServiceImpl implements DemoService {
    @Override
    public String sayHello(String name) {
        return "Hello " + name;
    }
}

用 Spring 配置宣告暴露服務
provider.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://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"
>
<!-- 當前專案在整個分散式架構裡面的唯一名稱,用於計算依賴關係 --> <dubbo:application name="helloworld-app" /> <!--dubbo這個服務所要暴露的服務地址所對應的註冊中心,N/A為不使用註冊中心--> <dubbo:registry address="N/A"/> <!--當前服務釋出所依賴的協議;webserovice、Thrift、Hessain、http--> <dubbo:protocol name="dubbo" port="20880"/> <!--服務釋出的配置,需要暴露的服務介面--> <dubbo:service interface="com.st.DemoService" ref="demoService"/> <!--bean的定義--> <bean id="demoService" class="com.st.DemoServiceImpl"/> </beans>

載入 Spring 配置

public class Provider {

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
        context.start();
        System.in.read(); // 按任意鍵退出
    }
}

服務消費者

consumer.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://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣 -->
    <dubbo:application name="consumer-of-helloworld-app"/>

    <dubbo:registry address="N/A"/>

    <!-- 生成遠端服務代理,可以和本地bean一樣使用demoService -->
    <dubbo:reference id="demoService" interface="com.st.DemoService"
                     url="dubbo://localhost:20880/com.st.DemoService"/>

</beans>

載入Spring配置,並呼叫遠端服務

public class Consumer {

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
        context.start();
        // 獲取遠端服務代理
        DemoService demoService = (DemoService)context.getBean("demoService");
        // 執行遠端方法
        String hello = demoService.sayHello("world");
        // Hello world
        System.out.println( hello );
    }
}

這就是典型的點對點的服務呼叫。當然我們為了高可用,可以在consumer.xml中配置多個服務提供者,並配置響應的負載均衡策略

配置多個服務呼叫者在comsumer.xml的<dubbo:reference>標籤的url屬性中加入多個地址,中間用分號隔開即可
配置負載均衡策略在comsumer.xml的<dubbo:reference>標籤中增加loadbalance即可,值可以為如下四種類型

  1. RoundRobin LoadBalance,隨機,按權重設定隨機概率。
  2. RoundRobin LoadBalance,輪詢,按公約後的權重設定輪詢比率。
  3. LeastActive LoadBalance,最少活躍呼叫數,相同活躍數的隨機,活躍數指呼叫前後計數差。
  4. ConsistentHash LoadBalance,一致性 Hash,相同引數的請求總是發到同一提供者。
<dubbo:reference id="demoService" interface="com.st.DemoService"
				 url="dubbo://192.168.11.1:20880/com.st.DemoService;
				 dubbo://192.168.11.2:20880/com.st.DemoService;
				 dubbo://192.168.11.3:20880/com.st.DemoService"
				 loadbalance="roundrobin"/>

現在整體架構是如下圖(假設服務消費者為訂單服務,服務提供者為使用者服務):

在這裡插入圖片描述

這樣會有什麼問題呢?

  1. 當服務提供者增加節點時,需要修改配置檔案
  2. 當其中一個服務提供者宕機時,服務消費者不能及時感知到,還會往宕機的服務傳送請求

這個時候就得引入註冊中心了

註冊中心

Dubbo目前支援4種註冊中心,(multicast zookeeper redis simple) 推薦使用Zookeeper註冊中心,本文就講一下用zookeeper實現服務註冊和發現(敲黑板,又一種zookeeper的用處)
在這裡插入圖片描述

現在我們來看Dubbo官網對Dubbo的介紹圖,有沒有和我們上面畫的很相似
在這裡插入圖片描述
節點角色說明

節點 角色說明
Provider 暴露服務的服務提供方
Consumer 呼叫遠端服務的服務消費方
Registry 服務註冊與發現的註冊中心
Monitor 統計服務的呼叫次數和呼叫時間的監控中心
Container 服務執行容器

呼叫關係說明

  1. 服務容器負責啟動(上面例子為Spring容器),載入,執行服務提供者。
  2. 服務提供者在啟動時,向註冊中心註冊自己提供的服務。
  3. 服務消費者在啟動時,向註冊中心訂閱自己所需的服務。
  4. 註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連線推送變更資料給消費者。
  5. 服務消費者,從提供者地址列表中,基於軟負載均衡演算法,選一臺提供者進行呼叫,如果呼叫失敗,再選另一臺呼叫。
  6. 服務消費者和提供者,在記憶體中累計呼叫次數和呼叫時間,定時每分鐘傳送一次統計資料到監控中心。

要使用註冊中心,只需要將provider.xml和consumer.xml更改為如下

<!--<dubbo:registry address="N/A"/>-->
<dubbo:registry protocol="zookeeper" address="192.168.11.129:2181"/>

如果zookeeper是一個叢集,則多個地址之間用逗號分隔即可

<dubbo:registry protocol="zookeeper" address="192.168.11.129:2181,192.168.11.137:2181,192.168.11.138:2181"/>

把consumer.xml中配置的直連的方式去掉

<!-- 生成遠端服務代理,可以和本地bean一樣使用demoService -->
<!--<dubbo:reference id="demoService" interface="com.st.DemoService"-->
                 <!--url="dubbo://localhost:20880/com.st.DemoService"/>-->


<dubbo:reference id="demoService" interface="com.st.DemoService"/>

註冊資訊在zookeeper中如何儲存?

啟動上面服務後,我們觀察zookeeper的根節點多了一個dubbo節點及其他,圖示如下
在這裡插入圖片描述
最後一個節點中192.168.1.104是小編的內網地址,你可以任務和上面配置的localhost一個效果,並且這個url中引數省略了,完整地址為。

dubbo://192.168.1.104:20880/com.st.DemoService?anyhost=true&application=helloworld-app&dubbo=2.5.3&interface=com.st.DemoService&methods=sayHello&pid=13360&side=provider&timestamp=1544257793335

大家可以想一下我為什麼把最後一個節點標成綠色的。沒錯,最後一個節點是臨時節點,而其他節點是持久節點,這樣,當服務宕機時,這個節點就會自動消失,不再提供服務,服務消費者也不會再請求。如果部署多個DemoService,則providers下面就是DemoService的所有服務地址

其實一個zookeeper叢集能被多個應用公用,如小編Storm叢集和Dubbo配置的就是一個zookeeper叢集,為什麼呢?因為不同的框架會在zookeeper上建不同的節點,互不影響。如dubbo會建立一個/dubbo節點,storm會建立一個/storm節點,如圖

在這裡插入圖片描述

參考部落格

[1]http://dubbo.apache.org/zh-cn/