Dubbo概述

(个人学习笔记,如有错误欢迎指正!!!)

相关概念

分布式的服务框架,主要是提供高性能的以及透明化的RPC远程服务调用解决方案,以及SOA服务治理方案

Dubbo的核心部分:

远程通信

集群容错

服务的自动发现

负载均衡

Dubbo架构

dubbo需要的spring版本 dubbo version_dubbo

Provider:服务的提供者

Consumer:服务的消费者

Registry:负责发现服务和配置服务

Container:管理服务的生命周期

Monitor:计算服务调用数量和耗时

使用方式

直连方式:

服务端

首先定义提供服务的接口,注意接口和后面的定义provider需要定义在两个工程或者两个模块中,提供服务的接口之后需要打成包提供给客户端。

public interface IOrderServices {
    DoOrderResponse doOrder(DoOrderRequest request);
}

然后将提供服务接口的项目打成jar包,可以使用 mvn clean package命令,或者直接使用 mvn clean istall命令将生成的jar包直接安装到本地仓库(如果客户端和服务端均是再本地进行测试)

然后再provider项目或者模块中创建提供服务接口的实现类:

public class OrderServiceImpl implements IOrderServices {
    @Override
    public DoOrderResponse doOrder(DoOrderRequest request) {
        System.out.println("request is coming");
        DoOrderResponse response = new DoOrderResponse();
        response.setCode("1000");
        response.setMemo("success");
        return response;
    }
}

此外,为了使用dubbo矿建,需要导入dubbo的依赖包,版本可以根据需要自行选择:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.5.3</version>
</dependency>

再provider项目中,还需要再src/main/resource目录下创建 META-INF/spring/${filename}.xml文件,该文件是对dubbo框架的一些定义:

<?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="order-provider" owner="clq"/>
    <!--不使用注册中心-->
    <dubbo:registry address="N/A"/>
    <!--当前服务发布所依赖的协议:webservice、Thrift、Hessain、http-->
    <dubbo:protocol name="dubbo" port="20880"/>
    <!--服务发布额配置,需要暴露的服务接口-->
    <dubbo:service interface="CLQ.IOrderServices" ref="orderService"/>
    <!--bean定义-->
    <bean id="orderService" class="CLQ.OrderServiceImpl"/>

</beans>

然后启动服务端的主方法:

public class App 
{
    public static void main( String[] args )
    {
        Main.main(args);
    }
}
客户端

客户端同样需要配置相应的依赖关系,其中第一个依赖是上面服务器端提供服务接口的项目的依赖包,因为在本地进行测试,所以直接可以从本地仓库中加载该依赖,也可以采用直接将生成的jar包直接导入到该项目中。第二个是所依赖的dubbo的依赖包

<dependency>
    <groupId>CLQ</groupId>
    <artifactId>order-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.5.3</version>
</dependency>

同样,客户端也需要对dubbo进行配置,在src/main/resource目录下创建${filename}.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="order-consumer" owner="clq"/>
    <!--不使用注册中心-->
    <dubbo:registry address="N/A"/>
    <!--生成一个一个远程服务的调用代理,并且指定访问的url,该url是服务端的ip:port以及服务接口组成的-->
    <dubbo:reference id="orderServices" interface="CLQ.IOrderServices"
        url="dubbo://192.168.2.167:20880/CLQ.IOrderServices"/>


</beans>

客户端启动的主方法:

public class App 
{
    public static void main( String[] args )
    {
        ClassPathXmlApplicationContext context = new 			ClassPathXmlApplicationContext("order-consumer.xml");
        IOrderServices services = (IOrderServices)context.getBean("orderServices");
        DoOrderRequest request = new DoOrderRequest();
        request.setName("clq");
        DoOrderResponse response = services.doOrder(request);
        System.out.println(response);
    }
}

注册中心(zookeeper服务器)

使用注册中心的方式和直接使用点对点的方式中java代码是相同的,只需要使用修改dubbo的配置文件:

服务端

主要添加注册中心的地址:

<?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="order-provider" owner="clq"/>
    <!--dubbo这个服务所要暴露的服务地址所对应的注册中心-->
    <dubbo:registry protocol="zookeeper" address="192.168.149.128:2181,192.168.149.130:2181,192.168.149.129:2181"/>
    <!--当前服务发布所依赖的协议:webservice、Thrift、Hessain、http-->
    <dubbo:protocol name="dubbo" port="20880"/>
    <!--服务发布额配置,需要暴露的服务接口-->
    <dubbo:service interface="CLQ.IOrderServices" ref="orderService"/>
    <!--bean定义-->
    <bean id="orderService" class="CLQ.OrderServiceImpl"/>

</beans>

也为这里注册中心使用的是zookeeper服务器,所以需要添加zookeeper的依赖:

<dependency>
    <groupId>com.101tec</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.10</version>
</dependency>
客户端

在客户端的配置中,童谣需要指定注册中心的地址,因为使用的是zookeeper服务器,所以同样需要添加zookeeper客户端的依赖,和服务器端相同。此外,与直连方式不同的是,不需要指定访问的url,客户端会自动从zookeeper注册中心获取url。

<?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="order-provider" owner="clq"/>
    <!--dubbo这个服务所要暴露的服务地址所对应的注册中心-->
    <dubbo:registry protocol="zookeeper" address="192.168.149.128:2181,192.168.149.130:2181,192.168.149.129:2181"/>
    <!--生成一个一个远程服务的调用代理-->
    <dubbo:reference id="orderServices" interface="CLQ.IOrderServices"/>
</beans>

设置

优先级:reference method > service method > reference > service > consumer > provider

对于消费者和提供者之间相同的配置,以优先级高的为准,消费者高于提供者

启动时检查

此外,dubbo:reference 有一个check属性,默认值为true

<dubbo:reference id="orderServices" interface="CLQ.IOrderServices" check="true"/>

如果为true,在启动时回去检查服务提供者是否正常提供服务,如果没有正常提供,即使没有调用该方法,也会出错

如果为false,则不会去检查,防止循环调用无法启动的情况

多协议支持

dubbo支持的协议:dubbo,hessian,RMI,webservice、http、Thrift

<dubbo:protocol name="dubbo" port="20880"/>
<dubbo:protocol name="hessian" port="8090" server="jetty"/>
<dubbo:service interface="CLQ.IOrderServices" ref="orderService" 	protocol="hessian,dubbo"/>
<bean id="orderService" class="CLQ.OrderServiceImpl"/>

可以在服务端dubbo配置文件中定义多个协议,同时指定service所使用的协议,可以指定多个协议,用逗号隔开,此时,运行服务端之后,查看zookeeper注册中心,可以发现生成了两个url节点,对应两个不同的协议

dubbo需要的spring版本 dubbo version_架构_02

对于客户端dubbo配置文件的修改,只需要指定使用的协议,也可以不指定,不指定时客户端会自动去适配

<dubbo:reference id="orderServices" interface="CLQ.IOrderServices" protocol="hessian"/>

注意,在使用hessian协议时,需要在服务端添加如下依赖:

<dependency>
    <groupId>com.caucho</groupId>
    <artifactId>hessian</artifactId>
    <version>4.0.38</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>
<dependency>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>jetty</artifactId>
    <version>6.1.26</version>
</dependency>

客户端因为要使用hessian协议,所以同样需要配置hessian依赖:

<dependency>
    <groupId>com.caucho</groupId>
    <artifactId>hessian</artifactId>
    <version>4.0.38</version>
</dependency>

异步调用

<dubbo:reference async="true"/>

将async字段设置为true表示异步调用,测试的时候不支持hessian协议,dubbo协议是可以的

然后客户端通过如下的方式异步获取数据:

DoOrderRequest request = new DoOrderRequest();
request.setName("clq");
services.doOrder(request);
Future<DoOrderResponse> response = RpcContext.getContext().getFuture();
DoOrderResponse response1 = response.get();
System.out.println(response1);

只订阅不注册

<dubbo:registry protocol="zookeeper" address="192.168.149.128:2181,192.168.149.130:2181,192.168.149.129:2181" register="false"/>

可以调用注册中心的服务,但是自己定义的服务不会注册到服务中心

只注册不订阅

只提供服务,不订阅服务

<dubbo:registry protocol="zookeeper" address="192.168.149.128:2181,192.168.149.130:2181,192.168.149.129:2181" subscribe="false"/>

负载均衡

Random:默认是随机

roundRobin:轮询,按照公约后的权重设置轮询比率

LeastActive LoadBalance:最少活跃调用,对于响应时间比较短的服务优先调用

Consistent LoadBalance:一致性hash,对于相同参数的请求都会落到相同的服务器

<dubbo:service interface="CLQ.IOrderServices" ref="orderService" protocol="dubbo" loadbalance="random"/>

连接超时

一定要设置服务处理超时时间

<dubbo:service interface="CLQ.IOrderServices" timeout="200" ref="orderService" protocol="dubbo"/>

集群容错

Failover Cluster:调用失败时,自动切换并重试其他服务器。通过retries=2,来设置重试次数,默认使用该机制

Failfast Cluster:快速失败,只发起一次调用

Failsafe Cluster:出现异常时,直接忽略异常

Failback Cluster:失败自动恢复,后台记录失败请求,定时重发

Forking Cluster:并行调用多个服务器,只要一个成功就立刻返回,只能应用在读请求

Broadcast Cluster:广播调用所有提供者,逐个调用,其中一台报错就会返回异常

<dubbo:reference id="orderServices" interface="CLQ.IOrderServices" protocol="dubbo" cluster="failfast"/>

注册中心缓存

当客户端启动时,会从注册中心上获取服务的url,并保存到缓存文件中,当注册中心不可用时,客户端可以从缓存文件中获取服务的url

<dubbo:registry protocol="zookeeper" file="d:/dubbo.cache" address="192.168.149.128:2181,192.168.149.130:2181,192.168.149.129:2181"/>

zookeeper注册中心

访问zookeeper注册中心,会发现根节点下会自动生成 /dubbo节点,该节便是保存服务端注册到注册中心的服务接口的相关信息:

dubbo需要的spring版本 dubbo version_管理控制_03

访问/dubbo节点的子目录,可以看到之前服务端注册的服务接口的信息(CLQ.IOrderServices),访问该接口节点的子节点,可以看到子节点中存在 providers节点,继续访问该节点,可以看到providers节点下有一个子节点,该节点的名字很长,实际上该节点的名字就是一个访问路径,用于客户端调用服务端提供的服务。

此外,这个提供url节点是一个临时节点,当服务端与注册中心的会话断开之后,该节点会被注册中心删除。

管理控制

Dubbo控制台

首先,下载dubbo源代码,访问源代码中dubbo-admin子模块(注意dubbo-2.6.0之后源代码中不存在该模块),该模块实际上是一个web项目

修改该模块的 dubbo-admin\src\main\webapp\WEB-INF\dubbo.properties文件中内容,指定所要访问的zookeeper注册中心的地址

dubbo.registry.address=zookeeper://192.168.149.128:2181?backup=192.168.149.130:2181,192.168.149.129:2181

因为该项目是maven项目,使用命令 mvn clean package对项目进行打包,会生成war包,部署到tomcat服务器上

然后访问部署时指定的路径:http://localhost:8080/dubbo_admin_war

此时会要求输入用户名密码,用户名密码均定义在 dubbo-admin\src\main\webapp\WEB-INF\dubbo.properties文件中:

dubbo.admin.root.password=root
dubbo.admin.guest.password=guest

注意用户名和密码相同

然后启动前面定义的提供者和消费者,便会在该界面上访问这些信息以及做一些控制。

dubbo需要的spring版本 dubbo version_架构_04

监控中心

在dubbo的源代码中找到dubbo-simple下的dubbo-monitor-simple子模块(注意dubbo-2.6.0之后没有该子模块),使用 mvn clean package命令对该项目进行打包,之后会在target目录下生成 dubbo-monitor-simple-2.6.0-assembly.tar.gz压缩包,注意不是jar包,将该压缩包解压之后,会有bin,conf,lib三个目录

访问conf/dubbo.properties文件,同样修改注册中心地址:

dubbo.container=log4j,spring,registry,jetty
dubbo.application.name=simple-monitor
dubbo.application.owner=
dubbo.registry.address=zookeeper://192.168.149.128:2181?backup=192.168.149.130:2181,192.168.149.129:2181
dubbo.protocol.port=7070
dubbo.jetty.port=8080
dubbo.jetty.directory=${user.home}/monitor
dubbo.charts.directory=${dubbo.jetty.directory}/charts
dubbo.statistics.directory=${user.home}/monitor/statistics
dubbo.log4j.file=logs/dubbo-monitor-simple.log
dubbo.log4j.level=WARN

monitor本身也是一个dubbo服务,使用proterties文件和使用xml文件是一样的

然后通过bin目录下的 start.bat

之后访问http://localhost:8080便可以访问控制中心页面

dubbo需要的spring版本 dubbo version_dubbo_05

telnet命令(超级难用)

该命令可以判断对应的服务是否可以连通,使用方式为 telnet ip port

例如 telnet localhost 20880

执行之后,还有如下常用命令:

  • ls:查看服务,对应于provider提供的接口以及接口中的方法

dubbo需要的spring版本 dubbo version_相关设置_06

  • invoke:调用服务接口

dubbo需要的spring版本 dubbo version_dubbo_07