Dubbo的使用,看这篇就够了

Dubbo

一、Dubbo概述

  1. Dubbo是一个Java RPC框架,用于提供高性能的远程服务调用方案和SOA服务治理方案

简单来说,Dubbo用于给消费方提供调用接口 (将接口注册到注册中心中)

  1. Dubbo运行流程图

在这里插入图片描述

节点角色说明:

● Provider: 暴露服务的服务提供方
● Consumer: 调用远程服务的服务消费方
● Container: 服务运行容器
● Registry: 服务注册与发现的注册中心
● Monitor: 统计服务的调用次数和调用时间的监控中心

  1. Dubbo运行流程文字解释

(1) 启动容器,加载运行服务提供方
(2) 提供方启动时,在注册中心注册自己提供的服务
(3) 消费方启动时,在注册中心订阅自己需要的服务
(4) 注册中心用于管理提供方提供的url;ZooKeeper是Dubbo推荐使用的注册中心
(5) 监控中心管理整个过程

  1. 考虑失败或变更的情况

(1) 注册中心返回提供方地址列表给消费方,如果有变更,注册中心推送变更数据给消费方
(2) 消费方从提供方地址列表中,选择一台提供者进行调用,如果调用失败,选择另一台
(3) 消费方和提供方在内存中记录调用次数和调用时间,每分钟发送一次统计数据给监控中心

二、Dubbo运行示例

创建两个模块,一个作为提供方,一个作为消费方,通过Dubbo来实现消费方远程调用服务方提供 的服务,分别启动双方,进行测试

注意:要求双方都是可独立运行的war项目,并不是通过maven依赖调用提供方的服务

在这里插入图片描述

  1. 双方都需要使用的接口的开发

将接口作为独立模块的原因:

(1) 提供方需要实现此接口定义具体的方法(服务),因而需要定义此接口
(2) 消费方需要定义此接口从而调用接口中的方法(使用此接口提供的服务)

导致双方对此接口的定义重复,一旦接口改动,双方修改繁琐,故将公用接口作为独立模块

package com.itheima.service;

public interface UserService {
    
    

    public String sayHello();
}
//并且需要将此模块install成为jar包


在这里插入图片描述

  1. 提供方开发

(1) pom.xml文件中的内容

<groupId>com.itheima</groupId>
<artifactId>dubbo-service</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<!-- war项目 -->

<!-- jar包版本控制 -->
<properties>
    <spring.version>5.1.9.RELEASE</spring.version>
    <dubbo.version>2.7.4.1</dubbo.version>
    <zookeeper.version>4.0.0</zookeeper.version>
</properties>

<dependencies>

    <!--Dubbo服务所需jar包-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo</artifactId>
        <version>${dubbo.version}</version>
    </dependency>

    <!--ZooKeeper服务所需jar包-->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>${zookeeper.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>${zookeeper.version}</version>
    </dependency>

    <!--依赖公共的接口模块-->
    <dependency>
        <groupId>com.itheima</groupId>
        <artifactId>dubbo-interface</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    <!--以及其余必须的如spring、springmvc、Log4J等jar包-->
    <!--以及tomcat服务器的插件-->
</dependencies>

在这里插入图片描述

(2) web.xml中的内容

<context-param>
    <param-name>contextConfigLocation</param-name>
<!-- 监听Spring配置文件 -->
    <param-value>classpath*:spring/applicationContext*.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

(3) UserServiceImpl中的内容

//导入公共接口所在类的包
/**
 * 1. @Service注解是Dubbo包下的,并不是Spring包下的
 * 2. 使用了此注解的类提供的方法将会对外发布,并将访问地址,端口等注册到注册中心中
 */
@Service
public class UserServiceImpl implements UserService {
    
    
    @Override
    public String sayHello() {
    
    
        return "hello Dubbo !";
    }
}

(4) applicationContext.xml中的内容

<!--Dubbo的配置-->

<!-- 1. 配置项目的名称(自定义),用于注册中心计算项目之间依赖关系,唯一 -->
<dubbo:application name="dubbo-service"/>

<!-- 2. 配置注册中心的地址,用于连接注册中心,address为Zookeeper所在Linux的ip地址及ZooKeeper端口号 -->
<dubbo:registry address="zookeeper://192.168.200.130:2181"/>

<!-- 3. 配置Dubbo的包扫描,使用了Dubbo包下的@Service注解的类会被发布为服务 -->
<dubbo:annotation package="com.itheima.service.impl" />

  1. 消费方开发

(1) pom.xml中的内容

<groupId>com.itheima</groupId>
<artifactId>dubbo-web</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<!-- war项目 -->

<!-- jar包版本控制 -->
<properties>
    <spring.version>5.1.9.RELEASE</spring.version>
    <dubbo.version>2.7.4.1</dubbo.version>
    <zookeeper.version>4.0.0</zookeeper.version>
</properties>

<dependencies>

    <!--Dubbo服务所需jar包-->
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo</artifactId>
        <version>${dubbo.version}</version>
    </dependency>

    <!--ZooKeeper服务所需jar包-->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
        <version>${zookeeper.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-recipes</artifactId>
        <version>${zookeeper.version}</version>
    </dependency>

    <!--依赖公共的接口模块-->
    <dependency>
        <groupId>com.itheima</groupId>
        <artifactId>dubbo-interface</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

	<!-- web模块并没有直接依赖service模块,通过远程调用方式 -->

    <!--以及其余必须的如spring、springmvc、Log4J等jar包-->
    <!--以及tomcat服务器的插件-->
</dependencies>


在这里插入图片描述

(2) web.xml中的内容

<!-- Springmvc -->   
   <servlet>
       <servlet-name>springmvc</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:spring/springmvc.xml</param-value>
       </init-param>
   </servlet>
   <servlet-mapping>
       <servlet-name>springmvc</servlet-name>
       <url-pattern>/</url-pattern>
   </servlet-mapping>

(3) UserController中的内容

//导入公共接口所在类的包
@RestController
@RequestMapping("/user")
public class UserController {
    
    
    /**
     * 1. @Reference注解导入的为Dubbo包
     * 2. @Reference注解作用:
     *    (1) 从zookeeper注册中心获取提供方的访问url
     *    (2) 进行远程调用RPC
     *    (3) 将结果封装为一个代理对象,赋值给userService对象
    */
    @Reference
    private UserService userService;

    @RequestMapping("/sayHello")
    public String sayHello(){
    
    
        return userService.sayHello();
    }
}

(4) springmvc.xml中的内容

<mvc:annotation-driven/>
<!-- 扫描使用了Controller注解的类 -->
<context:component-scan base-package="com.itheima.controller"/>

<!--dubbo的配置-->
<!-- 1.配置项目的名称,唯一 -->
<dubbo:application name="dubbo-web" >
    <!-- 在同一台机器上同时部署提供方和消费方需要区分二者,否则二者同时使用默认端口22222,冲突 -->
    <!-- 实际开发中,提供方与消费方通常部署在不同的机器上,无需关心此项-->
    <dubbo:parameter key="qos.port" value="33333"/>
</dubbo:application>
<!-- 2. 配置注册中心的地址-->
<dubbo:registry address="zookeeper://192.168.200.130:2181"/>
<!-- 3. 配置dubbo包扫描,扫描使用了Dubbo包下的@Reference注解 -->
<dubbo:annotation package="com.itheima.controller" />

  1. 运行结果

(1) 对service模块、web模块分别运行此指令,作为提供方和消费方的两个war项目

在这里插入图片描述

(2) web模块运行之后的日志信息如下

在这里插入图片描述

(3) 运行效果如下

在这里插入图片描述

三、序列化

当提供方(生产者)与消费方(消费者)需要传递Pojo类型时,需要使Pojo类实现IO包下的Serializable 接口,成为二进制流进行传输

四、地址缓存

  1. 问:当注册中心挂了之后,服务是否可以正常访问

  2. 答:可以;因为消费者在第一次调用服务时,会将生产者的地址缓存到本地,之后访问此地址时 不会再经过注册中心;当生产者的地址发生变化之后,注册中心通过notify机制通知消费者 新地址;
    注意:注册中心挂了之后,已经存在的消费者可以访问服务,但新的消费者将无法进行访问

五、超时

  1. 消费者在调用生产者的服务时,如果发生了阻塞、等待等情况,消费者会一直等待下去

  2. 在某个峰值时刻,如果大量的请求阻塞,会造成雪崩现象

  3. Dubbo使用超时机制解决此问题,设置一个超时时间,如果在此时间内无法完成服务的访问,则 自动断开连接,并报timeout错误

  4. 使用timeout属性配置超时时间,默认值1000,单位毫秒

//timeout属性设置超时时间,单位毫秒;
@Service(timeout = 3000)
  1. 消费者的@Reference注解也可使用timeout属性,但一般建议使用在生产者中,因为在生产者中 定义服务,可以预估需要的时间,方便进行超时设置

六、重试

  1. 设置了超时时间,在此时间内如果无法完成服务的调用,会自动断开连接并报错

  2. 如果出现网络抖动(网络不稳定短暂中断但很快恢复),则此次请求就会失败

  3. Dubbo使用重试机制避免此类问题的发生

  4. 通过retries属性设置重试次数,默认为两次(加上第一次的请求,共三次)

//retries属性设置重传次数
@Service(timeout = 3000, retries = 3)

七、多版本

  1. 当生产者的服务出现新版本时,并不会让所有的消费者访问此版本,而是会让一部分消费者先调 用此版本,确认没有问题之后再让所有消费者调用此版本,称为灰度发布

  2. Dubbo中使用version属性设置和调用同一个接口的不同版本

生产者代码:

@Service(version = "v1.0", timeout = 3000)
public class UserServiceImpl1 implements UserService {
    
    ...}

@Service(version = "v2.0")
public class UserServiceImpl2 implements UserService {
    
    ...}

消费者代码:

@Reference(version = "v2.0")
private UserService userService;
//成功调用v2.0版本的服务

八、负载均衡

  1. 消费者访问生产者集群,需要使用负载均衡策略,有四种:

(1) Random:默认策略;按权重设置随机概率,权重越高,越容易被访问
(2) RoundRobin:按请求先后轮询
(3) LeastActive:响应时间越短越容易被访问
(4) ConsistentHash:相同的请求总是调用同一个服务

注意:四种策略与Nginx的负载均衡策略类似

  1. 生产者配置,通过weight属性设置权重,默认值为100
@Service(weight = 200)
  1. 消费者配置,通过loadbalance属性设置策略,默认值为random
@Reference(loadbalance = "random")
@Reference(loadbalance = "roundrobin")
@Reference(loadbalance = "leastactive")
@Reference(loadbalance = "consistenthash")
  1. 注意:同一台机器上启动多个服务,需要修改以下两个端口,每个服务都不可相同,防止冲突

在这里插入图片描述

九、集群容错

  1. 集群容错模式有以下几种:

(1) Failover Cluster: 默认模式;失败重试,默认重试两次,使用retries配置;当出现失败,报错, 并重试其它服务器两次,一般用于读操作,写操作可能由于延迟等导致写入数据重复

(2) Failfast Cluster : 快速失败;发起一次调用,如果失败立即报错,不会重试,通常用于写操作

(3) Failsafe Cluster: 失败安全,出现异常时,不报错,直接忽略,返回一个空结果

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

(5) Forking Cluster : 并行调用多个服务,只要一个成功即返回

(6) Broadcast Cluster: 广播调用所有提供者,逐个调用,任意一个调用失败则报错

  1. 消费者配置,使用cluster属性设置集群容错模式,默认值为failover
@Reference(cluster = "failover")

十、服务降级

  1. 当服务器压力较大时,根据实际情况,释放某些服务,仅保留核心服务以保证服务整体高效运作

  2. 服务降级方式有如下两种

(1) mock = force:return null:表示消费者对该服务的调用都是返回空值,相当于把服务屏蔽

(2) mock = fail:return null:表示消费方对该服务的调用在失败后(会重试),再返回空值,不报错

  1. 消费方配置,使用mock属性设置服务降级方式
@Reference(mock = "force : return null")

猜你喜欢

转载自blog.csdn.net/weixin_49343190/article/details/112982259