GinoBeFunny

动手学dubbo之初体验

dubbo是阿里巴巴开源的分布式服务框架,本篇通过源码中的demo快速了解dubbo的架构、核心概念和开发方式。

一. 概述

以下部分来源于dubbo用户指南.

DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

dubbo架构

1
2
3
4
5
6
0. Container负责启动、加载、运行Provider;
1. Provider在启动时向注册中心注册自己提供的服务;
2. Consumer在启动时向注册中心订阅自己所需的服务;
3. Registry返回Provider地址列表给Consumer,如有变更,Registry将基于长连接推送变更数据给Consumer;
4. Consumer从Provider地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用;
5. Consumer和Provider在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到Monitor。

二. 把demo跑起来

  1. fork dubbo源码
  2. clone dubbo源码
    git clone git@github.com:ginobefun/dubbo.git
    
  3. 编译源码
    cd dubbo
    mvn clean install -Dmaven.test.skip=true
    
  4. 启动简易Registry
    解压dubbo-simple\dubbo-registry-simple\target\dubbo-registry-simple-VERSION-SNAPSHOT-assembly.tar.gz到临时目录tmp\并重命名为dubbo-registry-simple;
    执行dubbo-registry-simple\bin\start.bat启动;
    控制台输出“Dubbo service server started!”则启动成功;
    
  5. 启动简易Monitor
    解压dubbo-simple\dubbo-monitor-simple\target\dubbo-monitor-simple-VERSION-SNAPSHOT-assembly.tar.gz到临时目录tmp\并重命名为dubbo-monitor-simple;
    修改dubbo-monitor-simple\conf\dubbo.properties中“dubbo.registry.address=dubbo://127.0.0.1:9090”;
    执行dubbo-monitor-simple\bin\start.bat启动;
    控制台输出“Dubbo service server started!”则启动成功;
    
  6. 启动provider示例
    解压dubbo-demo\dubbo-demo-provider\target\dubbo-demo-provider-VERSION-SNAPSHOT-assembly.tar.gz到临时目录tmp\并重命名为dubbo-demo-provider;
    修改dubbo-demo-provider\conf\dubbo.properties中“dubbo.registry.address=dubbo://127.0.0.1:9090”;
    执行dubbo-demo-provider\bin\start.bat启动;
    控制台输出“Dubbo service server started!”则启动成功;
    
  7. 启动consumer示例
    解压dubbo-demo\dubbo-demo-consumer\target\dubbo-demo-consumer-VERSION-SNAPSHOT-assembly.tar.gz到临时目录tmp\并重命名为dubbo-demo-consumer;
    修改dubbo-demo-consumer\conf\dubbo.properties中“dubbo.registry.address=dubbo://127.0.0.1:9090”;
    执行dubbo-demo-consumer\bin\start.bat启动;
    
  8. 观察demo-provider控制台输出
    [10:44:21] Hello world0, request from consumer: /192.168.56.1:50832
    [10:44:23] Hello world1, request from consumer: /192.168.56.1:50832
    [10:44:25] Hello world2, request from consumer: /192.168.56.1:50832
    [10:44:27] Hello world3, request from consumer: /192.168.56.1:50832
    ......
    
  9. 观察demo-consumer控制台输出
    [10:44:21] Hello world0, response form provider: 192.168.56.1:20880
    [10:44:23] Hello world1, response form provider: 192.168.56.1:20880
    [10:44:25] Hello world2, response form provider: 192.168.56.1:20880
    [10:44:27] Hello world3, response form provider: 192.168.56.1:20880
    ......
    
  10. 通过Monitor查看
    dubbo_monitor_home.png

dubbo_monitor_apps.png

dubbo_monitor_services.png

三. 翻一翻demo源码

先翻一翻相关的源码,下一篇开始深入学习具体的源码。

3.1 dubbo-registry-simple

简易注册中心服务实现

该类继承了抽象注册中心实现。
dubbo_registry_simple_service.png

从源码可以看出其实现是通过内存中两个ConcurrentHashMap来存放服务注册和订阅信息。
dubbo_registry_simple_service_structure.png

spring配置

在spring配置里引入了dubbo的多个命名空间,定义了application、protocol和service。

<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-2.5.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

  <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="location" value="classpath:dubbo.properties" />
  </bean>
  <dubbo:application name="${dubbo.application.name}" owner="${dubbo.application.owner}" />
  <dubbo:protocol name="dubbo" port="${dubbo.protocol.port}" heartbeat="180000" />
  <dubbo:service id="registryServiceConfig" interface="com.alibaba.dubbo.registry.RegistryService"
                 ref="registryService" registry="N/A" ondisconnect="disconnect" callbacks="1000">
    <dubbo:method name="subscribe"><dubbo:argument index="1" callback="true" /></dubbo:method>
    <dubbo:method name="unsubscribe"><dubbo:argument index="1" callback="false" /></dubbo:method>
  </dubbo:service>
  <bean id="registryService" class="com.alibaba.dubbo.registry.simple.SimpleRegistryService" />
</beans>

dubbo配置

dubbo.container=log4j,spring
dubbo.application.name=simple-registry
dubbo.application.owner=
dubbo.protocol.port=9090
dubbo.log4j.file=logs/dubbo-simple-registry.log
dubbo.log4j.level=WARN

3.2 dubbo-demo-api

定义了服务的接口。

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

3.3 dubbo-demo-provider

DemoService的实现

public class DemoServiceImpl implements DemoService {
    public String sayHello(String name) {
        System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello "
                 + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
        return "Hello " + name + ", response form provider: " + RpcContext.getContext().getLocalAddress();
    }
}

Spring配置

通过dubbo:service导出服务。

<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-2.5.xsd
          http://code.alibabatech.com/schema/dubbo          
          http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />
    <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" />
</beans>

dubbo配置

dubbo.container=log4j,spring
dubbo.application.name=demo-provider
dubbo.application.owner=
dubbo.registry.address=dubbo://127.0.0.1:9090
dubbo.monitor.protocol=registry
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.service.loadbalance=roundrobin
dubbo.log4j.file=logs/dubbo-demo-provider.log
dubbo.log4j.level=WARN

3.4 dubbo-demo-consumer

DemoAction引用DemoService服务。

public class DemoAction {
    private DemoService demoService;

    public void setDemoService(DemoService demoService) {
        this.demoService = demoService;
    }

    public void start() throws Exception {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            try {
                String hello = demoService.sayHello("world" + i);
                System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] " + hello);
            } catch (Exception e) {
                e.printStackTrace();
            }
            Thread.sleep(2000);
        }
    }
}

Spring配置

<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-2.5.xsd
          http://code.alibabatech.com/schema/dubbo
          http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" />
    <bean class="com.alibaba.dubbo.demo.consumer.DemoAction" init-method="start">
        <property name="demoService" ref="demoService" />
    </bean>
</beans>

dubbo配置

dubbo.container=log4j,spring
dubbo.application.name=demo-consumer
dubbo.application.owner=
dubbo.registry.address=dubbo://127.0.0.1:9090
dubbo.monitor.protocol=registry
dubbo.log4j.file=logs/dubbo-demo-consumer.log
dubbo.log4j.level=WARN

3.5 dubbo-monitor-simple

//TODO: 暂时跳过,后续详解

四. 初体验感受

  1. 通过阅读用户指南和Quick Start能够快速了解dubbo的全貌和初步的开发体验;
  2. 通过阅读源码可以看出dubbo的架构设计很清晰且易于扩展;
  3. 后续的文章将会根据Quick Start的例子一步步了解dubbo的实现以加深理解。

参考资源

Gino Zhang wechat
扫一扫,关注我的微信公众号