dubbo簡易實現_分別利用自定義的註冊中心和zookeeper

dubbo + (點對點型、zookeeper)整合,理解其思想,熟悉其基本流程

2017-06-25

(github地址:https://github.com/jiangcaijun/dubbo)html

一、dubbo的設計思想

這裏輸入引用文本Dubbo是一個分佈式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案,以服務者與消費者的方式在dubbo上註冊java

dubbo的架構圖,以下(圖片來源於internet)git

dubbo的架構圖

Provider: 暴露服務的服務提供方。 Consumer: 調用遠程服務的服務消費方。 Registry: 服務註冊與發現的註冊中心。 Monitor: 統計服務的調用次調和調用時間的監控中心。 Container: 服務運行容器。github

調用關係說明:算法

  1. 服務容器負責啓動,加載,運行服務提供者。
  2. 服務提供者在啓動時,向註冊中心註冊本身提供的服務。
  3. 服務消費者在啓動時,向註冊中心訂閱本身所需的服務。
  4. 註冊中心返回服務提供者地址列表給消費者,若是有變動,註冊中心將基於長鏈接推送變動數據給消費者。
  5. 服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一臺提供者進行調用,若是調用失敗,再選另外一臺調用。
  6. 服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鐘發送一次統計數據到監控中心。

參考自:Dubbo與Zookeeper、SpringMVC整合和使用(負載均衡、容錯) - 好庫文摘spring

二、自定義實現註冊中心

新建三個項目,均用maven進行管理,基於JDK1.7。實現點對點的生產與消費。apache

  • dubbo-api (註冊中心:服務註冊與發現的註冊中心)
  • dubbo-provider(生產者:暴露服務的服務提供方)
  • dubbo-consumer(消費者:調用遠程服務的服務消費方)

2.1 dubbo-api (註冊中心)

新建該項目,其pom以下api

<groupId>com.dubbo.demo</groupId>
<artifactId>dubbo-api</artifactId>
<version>1.0-SNAPSHOT</version>

新建一個接口,生產者將會負責該接口的實現,消費者將會調用該接口tomcat

package com.dubbo.demo;

public interface IHelloWorld {
    public String sayHello(String name);

    public Object doSomeThing();
}

接着,利用maven install將其發佈至本地倉庫中,生產者與消費者將均會在pom.xml中引入該依賴。架構

其項目結構如圖:

dubbo-api (註冊中心)結構圖

2.2 dubbo-provider (生產者)

新建該項目,其pom以下。

<groupId>com.dubbo.demo.provider</groupId>
<artifactId>dubbo-provider</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
    <slf4j.version>1.7.21</slf4j.version>
</properties>
<dependencies>
    <dependency>
        <groupId>com.dubbo.demo</groupId>
        <artifactId>dubbo-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dubbo</artifactId>
        <version>2.5.3</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
</dependencies>

該生產者引入了dubbo-api (註冊中心)和dubbo的依賴,同時爲了方便調試,還添加了日誌相關依賴。

實現dubbo-api (註冊中心)的接口

package com.dubbo.demo.provider;

import com.dubbo.demo.IHelloWorld;

public class HelloWorldServiceImpl implements IHelloWorld {

    public String sayHello(String name) {
        return "Hello World  " + name + ", I come from dubbo-api " ;
    }

    public Object doSomeThing() {
        return "i am doSomeThing, I come from dubbo-api " ;
    }
}

在resource目錄下新建配p2p_provider.xml,暴露IHelloWorld接口

<?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="hello_world_provider" owner="jcj" />

    <!--表示咱們的服務註冊到哪一個位置-->
    <dubbo:registry address="N/A"></dubbo:registry>

    <!-- 用dubbo協議在20880端口暴露服務 -->
    <dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>

    <!-- 具體的實現bean -->
    <bean id="helloService" class="com.dubbo.demo.provider.HelloWorldServiceImpl" />

    <!-- 聲明須要暴露的服務接口 -->
    <dubbo:service interface="com.dubbo.demo.IHelloWorld" ref="helloService" />

</beans>

同時新建一個dubboTest方法,用來啓動dubbo-provider (生產者)。

public class dubboTest {

    public static void main(String []args) throws IOException {

        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(new String("provider.xml"));

        classPathXmlApplicationContext.start();

        System.in.read();
    }
}

其項目結構如圖(圖中紅圈表明其引入了dubbo-api(註冊中心)的依賴):

dubbo-provider (生產者)結構圖

2.3 dubbo-consumer (消費者)

其pom和dubbo-provider (生產者)相似,均須要引入dubbo-api (註冊中心)和dubbo的依賴。

在resource目錄下新建p2p_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="hello_world_provider" owner="jcj" />

    <!--表示咱們的服務註冊到哪一個位置-->
    <dubbo:registry address="N/A"></dubbo:registry>

    <!-- 聲明須要暴露的服務接口 -->
    <dubbo:reference interface="com.dubbo.demo.IHelloWorld"
                   url="dubbo://127.0.0.1:20880/com.dubbo.demo.IHelloWorld"
                   id="helloService"></dubbo:reference>

</beans>

與dubbo-provider (生產者)的p2p_provider.xml比較,均聲明須要暴露的服務接口,即暴露了dubbo-api(註冊中心)的接口方法。

新建一個測試方法dubboConsumerTest

import com.dubbo.demo.IHelloWorld;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;

public class dubboConsumerTest {

    public static void main(String []args) throws IOException {

        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(new String("p2p_consumer.xml"));

        IHelloWorld iHelloWorld = (IHelloWorld)classPathXmlApplicationContext.getBean("helloService");

        String result = iHelloWorld.sayHello("哈哈哈");

        System.out.println("dubboConsumerTest.main: " + result);

        Object object = iHelloWorld.doSomeThing();

        System.out.println("dubboConsumerTest.main: " + object.toString());
    }
}

其項目結構如圖(圖中紅圈表明其引入了dubbo-api(註冊中心)的依賴):

dubbo-consumer(消費者)結構圖

2.4 點對點型dubbo測試

先啓動dubbo-provider (生產者)的dubboTest方法,此時服務開始提供; 此時生產者控制檯輸出以下:

[ com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol ] - [ INFO ]  
[DUBBO] disconected from /192.168.58.1:54584,url:dubbo://192.168.58.1:20880/com.dubbo.demo.IHelloWorld?anyhost=true&application=hello_world_provider&channel.readonly.sent=true&codec=dubbo&dubbo=2.5.3&heartbeat=60000&interface=com.dubbo.demo.IHelloWorld&methods=doSomeThing,sayHello&owner=jcj&pid=15740&revision=1.0-SNAPSHOT&side=provider&timestamp=1498555464131, dubbo version: 2.5.3, current host: 127.0.0.1

再啓動dubbo-consumer (消費者)的dubboConsumerTest,嘗試調用該方法。 此時消費者控制檯輸出:

Refer dubbo service com.dubbo.demo.IHelloWorld from url
dubbo://127.0.0.1:20880/com.dubbo.demo.IHelloWorld?application=hello_world_provider&dubbo=2.5.3&interface=com.dubbo.demo.IHelloWorld&methods=doSomeThing,sayHello&owner=jcj&pid=8296&revision=1.0-SNAPSHOT&side=consumer&timestamp=1498555502597, dubbo version: 2.5.3, current host: 192.168.58.1
dubboConsumerTest.main: Hello World  哈哈哈, I come from dubbo-api 
dubboConsumerTest.main: i am doSomeThing, I come from dubbo-api

證實測試經過。

三、利用zookeeper實現註冊中心

3.1 zookeeper安裝

  • 安裝zookeeper前,務必已經安裝好Java環境
  • 下載地址:http://www.apache.org/dyn/closer.cgi/zookeeper/ ,我下載的是zookeeper-3.4.5.tar.gz版本的
  • tar -zxvf zookeeper-3.4.5.tar.gz解壓後,複製conf目錄下的zoo_sample.cfg ,即 cp zoo_sample.cfg zoo.cfg,(緣由:Zookeeper在啓動時會找這個文件做爲默認配置文件)
  • 啓動zookeeper
    • ./zkServer.sh start-foreground (能夠查看啓動日誌)
    • ./zkServer.sh start
  • 測試啓動結果
    • ./zkServer.sh status
    • zookeeper默認使用的TCP鏈接端口是2181
      • 查看61616端口是否打開: netstat -an | grep 2181
      • 經過 netstat -tlnp 查找佔用pid號
      • 查找到zookeeper對應的進程: ps -ef | grep zookeeper
  • 關閉zookkeeper
    • ./zkServer.sh stop

3.2 dubbo-provider (生產者)

在pom.xml中添加zookeeper相關依賴,dubbo-consumer (消費者)也須要添加

<!--zookeeper apache-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.6</version>
</dependency>
<!--zkclient-->
<dependency>
    <groupId>com.github.sgroschupf</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.1</version>
</dependency>

在resource目錄下新建zk_provider.xml,鏈接zookeeper

<!-- 提供方應用信息,用於計算依賴關係 -->
<dubbo:application name="hello_world_provider" owner="jcj" />

<!-- 使用zookeeper註冊中心暴露服務地址-->
<dubbo:registry address="zookeeper://182.254.xx.xx:2181" check="false" subscribe="false" register="" />

<!-- 用dubbo協議在20880端口暴露服務 -->
<dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>

<!-- 聲明須要暴露的服務接口 -->
<dubbo:service interface="com.dubbo.demo.IHelloWorld" ref="helloService" />

<!-- 具體的實現bean -->
<bean id="helloService" class="com.dubbo.demo.provider.HelloWorldServiceImpl" />

dubbo:registry 標籤一些屬性的說明:

  • 1)register是否向此註冊中心註冊服務,若是設爲false,將只訂閱,不註冊。
  • 2)check註冊中心不存在時,是否報錯。
  • 3)subscribe是否向此註冊中心訂閱服務,若是設爲false,將只註冊,不訂閱。
  • 4)timeout註冊中心請求超時時間(毫秒)。
  • 5)address能夠Zookeeper集羣配置,地址能夠多個以逗號隔開等。

dubbo:service標籤的一些屬性說明:

  • 1)interface服務接口的路徑
  • 2)ref引用對應的實現類的Bean的ID
  • 3)registry向指定註冊中心註冊,在多個註冊中心時使用,值爲dubbo:registry的id屬性,多個註冊中心ID用逗號分隔,若是不想將該服務註冊到任何registry,可將值設爲N/A
  • 4)register 默認true ,該協議的服務是否註冊到註冊中心。

以上,引用自:Dubbo與Zookeeper、SpringMVC整合和使用(負載均衡、容錯) - 好庫文摘

3.3 dubbo-consumer (消費者)

在resource目錄下新建zk_consumer.xml,鏈接zookeeper

<!-- 提供方應用信息,用於計算依賴關係 -->
<dubbo:application name="hello_world_provider" owner="jcj" />

<dubbo:registry address="zookeeper://182.254.xx.xx:2181" />

<!-- 生成遠程服務代理,能夠和本地bean同樣使用其接口 -->
<dubbo:reference id="helloService" interface="com.dubbo.demo.IHelloWorld" />

3.4 dubbo_ZK (測試)

運行各相應的xml文件,注意生產者與消費者的前後啓動順序,能夠在消費者的控制檯看到相應的預期輸出,測試經過。

4 FAQ

4.1 zookeeper沒有設置超時時間

當zookeeper註冊中心連不上時dubbo的線程時,因爲ZKClient默認的超時時間是Integer.MAX_VALUE,幾乎等於無限等待。由於系統有一些定時任務會比較頻繁地開啓新線程鏈接dubbo,因此致使的結果是tomcat一下子線程池就滿了,其它的不依賴dubbo的功能也被阻塞沒法使用。

解決方案:dubbo鏈接zookeeper註冊中心由於斷網致使線程無限等待問題

4.2dubbo與zookeeper的關係

dubbo:是管理中間層的工具,在業務層到數據倉庫間有很是多服務的接入和服務提供者須要調度,dubbo提供一個框架解決這個問題。

注意這裏的dubbo只是一個框架,至於你架子上放什麼是徹底取決於你的,就像一個汽車骨架,你須要配你的輪子引擎。這個框架中要完成調度必需要有一個分佈式的註冊中心,儲存全部服務的元數據,你能夠用zk,也能夠用別的,例如:

  • Multicast註冊中心
  • Zookeeper註冊中心
  • Redis註冊中心
  • Simple註冊中心

5 參考連接

相關文章
相關標籤/搜索