分布式RPC系统框架Dubbo

newfarhui 2020-01-30

导读

Apache Dubbo是一款高性能轻量级开源Java RPC框架,它提供了三大核心能力;面向接口远程方法调用智能容错负载均衡,以及服务自动注册发现

dubbo官网:点我直达

第一个Dubbo程序(小试牛刀)

创建业务接口工程

项目结构

分布式RPC系统框架Dubbo

创建包和接口类

分布式RPC系统框架Dubbo

安装项目

分布式RPC系统框架Dubbo

创建提供者Provider工程

项目结构

分布式RPC系统框架Dubbo

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.cyb</groupId>
    <artifactId>02-first-provider</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--编译器依赖-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>13</maven.compiler.source>
        <maven.compiler.target>13</maven.compiler.target>
        <!--自定义版本号-->
        <spring-version>4.3.16.RELEASE</spring-version>
    </properties>
    <dependencies>
        <!--自定义工程依赖-->
        <dependency>
            <groupId>org.cyb</groupId>
            <artifactId>01-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--dubbo依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.7</version>
        </dependency>
        <!--netty-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>


        <!--spring依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>
    </dependencies>
</project>

注意

分布式RPC系统框架Dubbo

spring-dubbo-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="02-first-provider"/>
    <!--注册Service,将来服务的提供者-->
    <bean id="someService" class="com.cyb.service.SomeServiceImpl"></bean>
    <!--暴露服务,采用直连的方式-->
    <dubbo:service interface="com.cyb.service.SomeService" ref="someService" registry="N/A"></dubbo:service>
</beans>

SomeServiceImpl.java

package com.cyb.service;

public class SomeServiceImpl implements SomeService{
    @Override
    public String hello(String name) {
        System.out.println("Dubbo World Welcome You"+name);
        return "chenyanbin";
    }
}

RunProvider.java

package com.cyb.run;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

public class RunProvider {
    public static void main(String[] args) throws IOException {
        //创建spring容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring-dubbo-provider.xml");
        //启动spring容器
        ((ClassPathXmlApplicationContext) ac).start();
        //将当前主线程阻塞
        System.in.read();
    }
}

创建消费者Consumer工程

项目结构图

分布式RPC系统框架Dubbo

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.cyb</groupId>
    <artifactId>02-first-consumer</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--编译器依赖-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>13</maven.compiler.source>
        <maven.compiler.target>13</maven.compiler.target>
        <!--自定义版本号-->
        <spring-version>4.3.16.RELEASE</spring-version>
    </properties>

    <dependencies>
        <!--自定义工程依赖-->
        <dependency>
            <groupId>org.cyb</groupId>
            <artifactId>01-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--dubbo依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.7</version>
        </dependency>
        <!--netty-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>
        <!--spring依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring-version}</version>
        </dependency>
    </dependencies>
</project>

spring-dubbo-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="02-first-consumer"/>
    <!--消费引用-->
    <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" url="dubbo://localhost:20880"></dubbo:reference>
</beans>

注:端口号20880固定

RunConsumer.java

package com.cyb.run;

import com.cyb.service.SomeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class RunConsumer {
    public static void main(String[] args) {
        //创建Spring容器
        ApplicationContext ac=new ClassPathXmlApplicationContext("spring-dubbo-consumer.xml");
        SomeService service = (SomeService) ac.getBean("someSerivce");
        service.hello("tom");
    }
}

运行

分布式RPC系统框架Dubbo

Zookeeper注册中心&Zookeeper集群(Dubbo官网推荐)

拷贝生产者和消费者工程

分布式RPC系统框架Dubbo

注册中心其他方式

地址:http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html

分布式RPC系统框架Dubbo

Zookeeper工程搭建

配置参考地址:点我直达

启动zookeeper服务

分布式RPC系统框架Dubbo

修改提供者工程

pom.xml添加curator客户端依赖 

<!-- zk客户端依赖:curator-framework-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.1</version>
        </dependency>

注意事项

分布式RPC系统框架Dubbo

修改spring-dubbo-provider.xml

分布式RPC系统框架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="03-provider-zk"/>
    <!--注册Service,将来服务的提供者-->
    <bean id="someService" class="com.cyb.service.SomeServiceImpl"></bean>

    <!-- 声明zk服务中心 -->
    <!-- 单机版 -->
    <!-- 方式一 -->
    <dubbo:registry address="zookeeper://192.168.1.111:2181"/>
    <!-- 方式二 -->
    <!-- <dubbo:registry protocol="zookeeper" address=""/> -->

    <!-- 集群配置 -->
    <!-- 方式一 -->
    <!-- <dubbo:registry address="zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181" /> -->
    <!-- 方式二 -->
    <!-- <dubbo:registry protocol="zookeeper" address="10.20.153.10:2181,10.20.153.11:2181,10.20.153.12:2181" /> -->

    <!-- 同一Zookeeper,分成多组注册中心 -->
    <!-- <dubbo:registry id="chinaRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="china" />
    <dubbo:registry id="intlRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="intl" /> -->

    <!-- 暴露服务,将服务暴露给zk服务中心 -->
<!-- <dubbo:service interface="com.cyb.service.SomeService" ref="someService" registry="N/A"></dubbo:service> -->
    <dubbo:service interface="com.cyb.service.SomeService" ref="someService"></dubbo:service>

</beans>

修改消费者工程

pom.xml添加curator客户端依赖

<!-- zk客户端依赖:curator-framework-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.1</version>
        </dependency>

修改spring-dubbo-consumer.xml

分布式RPC系统框架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="03-consumer-zk"/>

    <!-- 声明zk服务中心 -->
    <!-- 单机版 -->
    <dubbo:registry address="zookeeper://192.168.1.111:2181"/>

    <!--消费引用-->
    <!-- <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" url="dubbo://localhost:20880"></dubbo:reference> -->
    <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService"></dubbo:reference>
</beans>

运行

分布式RPC系统框架Dubbo

Dubbo声明式缓存

   了进一步提高消费者对用户的响应速度减少提供者的压力Dubbo提供基于结果的声明式缓存。该缓存基于消费者端的,所以使用很简单,只需修改消费者配置文件与提供者无关

修改消费者配置文件

仅需在<dubbo:reference />中添加cache="true"即可

分布式RPC系统框架Dubbo

修改RunConsumer.java

分布式RPC系统框架Dubbo

缓存VS无缓存

先不加缓存,发现提供者执行2次,加上缓存提供者只执行一次

分布式RPC系统框架Dubbo

分布式RPC系统框架Dubbo

dubbo提供了三种结果缓存机制

  1. lru:服务级别缓存的默认机制。该机制默认可以缓存1000个结果。若超出1000,将采用最近最少使用原则来删除缓存,以保证最热的数据被缓存。
  2. threadlocal:当前线程缓存。当多个线程要对当前线程进行某一操作时首先需要查询当前线程的某个信息,通过线程缓存,则可有效减少查询。
  3. jcache:可以桥接各种缓存实现,即第三方缓存产品。

spring-dubbo-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="03-consumer-zk"/>

    <!-- 声明zk服务中心 -->
    <!-- 单机版 -->
    <dubbo:registry address="zookeeper://192.168.1.111:2181"/>

    <!-- <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" url="dubbo://localhost:20880"></dubbo:reference> -->
    <!-- <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService"></dubbo:reference> -->

    <!--消费引用:基于服务级别的声明式缓存(结果缓存)-->
    <!--<dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" cache="true"></dubbo:reference>-->

    <!--消费引用:基于方法级别的声明式缓存(结果缓存)-->
    <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" >
        <!--lru-->
        <dubbo:method name="hello" cache="lru"></dubbo:method>
        <!--threadlocal-->
        <dubbo:method name="hello" cache="threadlocal"></dubbo:method>
    </dubbo:reference>
</beans>

结果缓存的应用场景

Dubbo的结果缓存可以应用查询结果不变的场景。即不能使用在如下场景:消费者A调用的业务方法后从DB查询到一个结果a,此后,消费者B对DB中的该结果相关数据进行了修改,已使该查询结果变为b,但由于使用了结果缓存,消费者A中调用业务方法后的查询结果将长时间为a,直到该结果由于缓存空间满而被消除,否则,永远无法得到更新过的结果b。

多版本控制

Dubbo的多版本控制指的是,服务名称(接口名)相同的情况下提供不同的服务(实现类不同) ,然而消费者是通过服务名称(接口名)进行服务查询并进行消费的。提供者所提供的服务名称相同,如何让消费者通过名称进行服务查找呢?为服务添加一个版本号,使用“服务名称”+“版本号”的方式来唯一确定一个服务。

多版本控制主要的应用场景是:当一个接口的实现类需要升级时,可以使用版本号进行过渡(根据开闭原则,不能直接修改原实现类,只能添加新的实现类)。需要注意的是,版本号不同的服务间是不能互相引用的,因为新版本存在的目的是替换老版本。在生产环境中若存在多个提供者需要升级,一般不会一次性全部进行升级,而是会在低压力时间段先升级一部分,然后在下次再进行部分升级,直到全部升级完成。那么,这期间就需要使用版本号进行过渡。

项目准备

拷贝项目

分布式RPC系统框架Dubbo

提供者(04-provider-version)

分布式RPC系统框架Dubbo

修改配置文件

分布式RPC系统框架Dubbo

消费者(04-consumer-version)

分布式RPC系统框架Dubbo

执行

分布式RPC系统框架Dubbo

服务分组

   服务分组与多版本控制使用方式几乎是相同的,只要将version替换为group即可。但使用目的不同。使用版本控制的目的是为了升级,将原有老版本替换掉,将来不再提供老版本的服务,所以不同版本间不能出现相互调用。而分组目的则不同,其也是针对相同接口给出了多种实现类,但不同的是,这些不同实现并没有替换掉谁的意思,是针对不同需求,或针对不同功能模块锁给出的实现这些实现所提供的服务是并存的,所以他们间可以出现相互调用关系。例如,支付服务的实现,可以有微信支付实现与支付宝实现等。

服务暴露延迟

如果我们的服务启动过程中需要warmup事件(预热事件,与JVM重启后的预热过程相似,在启动后一小段事件后性能才能达到最佳状态)。比如初始化缓存,等待相关资源就位等。可以使用deplay进行延迟暴露。

值需要在服务提供者的<dubbo:service/>标签中添加delay属性,其值若为整数,则单位为毫秒,表示在指定事件后再发布服务;若为-1,则表示在spring初始化完毕后再暴露服务。

分布式RPC系统框架Dubbo

多注册中心

很多时候一个项目中会有多个注册中心。

同一个服务注册到多个中心

同一个服务可以注册不同地域的多个注册中心,以便为不同地域的服务消费者提供更为快捷的服务。

修改服务提供者配置文件。多个注册中心之间使用逗号分隔。

分布式RPC系统框架Dubbo

注:不是集群!!!

不同服务注册到不同中心

修改服务提供者配置文件

分布式RPC系统框架Dubbo

同一个服务引用自不同的中心

同一个消费者需要调用两个不同中心服务,而调用的该服务的名称(接口)、版本等都是相同的。不同中心的这个相同名称的服务调用时不同数据库中的数据,即相同服务最终执行的结果是不同的。

修改服务消费者配置文件

分布式RPC系统框架Dubbo

多协议支持

服务暴露协议

前面的示例中,服务提供者与服务消费者都是通过zookeeper连接协议连接上ZooKeeper注册中心的。

分布式RPC系统框架Dubbo

提供者与消费者均连接上了注册中心,那么消费者就理所当然的可以享受提供者提供的服务了么?

实际情况并不是这样的。前述ZooKeeper协议,是消费者/提供者连接注册中心的连接协议,而非消费者与提供者间的连接协议。

当消费者连接上注册中心后,在消费服务之前,首先需要连接上这个服务提供者。虽然消费者通过注册中心可以获取到服务提供者,但提供者对于消费者来说却是透明的,消费者并不知道真正的服务提供者是谁。不过,无论提供者是谁,消费者都必须连接上提供者才可以获取到真正的服务,而这个连接也是需要专门的连接协议的。这个协议称为服务暴露协议。

可是我们之前的代码示例中并没有看到服务暴露协议的相关配置,但仍可正常运行项目,这是为什么呢?因为采用了默认的暴露协议:Dubbo服务暴露协议。处理Dubbo服务暴露协议外,Dubbo框架还支持另外七种服务暴露协议:Hessian协议、HTTP协议、RMI协议、WebService协议、Thrift协议、Memcached协议、Redis协议;但在实际生产中,使用最多的就是Dubbo服务暴露协议。

Dubbo服务暴露协议,适合于小数据量大并发的服务调用,以及服务消费者主机数远大于服务提供者主机数的情况。

服务暴露协议用法

服务提供者的spring配置文件中首先需要注册暴露协议,然后在暴露服务时具体制定所使用的已注册的暴露协议。

分布式RPC系统框架Dubbo

注:protocol属性用于指定当前服务所使用的暴露协议

同一服务支持多种协议

直接修改服务提供者的配置文件

分布式RPC系统框架Dubbo

不同服务使用不同协议

直接修改服务提供者配置文件

分布式RPC系统框架Dubbo

Dubbo的高级设置及使用建议

在提供者上尽量多配置消费者端属性

提供者上尽量多配置消费者端的属性,让提供者实现着一开始就思考提供者服务特点、服务质量等问题。因为作服务的提供者,比服务使用方更清楚服务性能参数,如调用的超时时间、合理的重试次数等。在提供者端配置后,消费者不配置则会使用提供者端的配置值,即提供者配置可以作为消费者的缺省值。否则,消费者会使用消费者端的全局设置,这对提供者是不可控的,并且往往不合理的。

分布式RPC系统框架Dubbo

以下属性在<dubbo:method/>上则是针对指定方法,配置在<dubbo:service/>上则是针对整个服务。

  • timeout:远程服务调用超时时限。
  • retries:失败重试次数,默认值是2。
  • loadbalance:负载均衡算法,默认是随机的random。还可以有轮询roundrobin、最不活跃优先leastactive等。
  • actives:消费者最大并发调用限制,即当Consumer对一个服务的并发调用到上限后,新调用会阻塞直到超时。

提供者上配置合理的提供者端属性

分布式RPC系统框架Dubbo

  • threads:用于指定服务线程池大小
  • executes:一个服务提供者并行执行请求上限,即当提供者对一个服务的并发调用达到上限后,新调用会阻塞,此时消费者可能会超时,该属性配置在<dubbo:method/>上则是针对指定方法的,配置在<dubbo:service/>上则是针对整个服务

相关推荐