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 参考连接

相关文章
相关标签/搜索