高性能服务框架Dubbo

高性能服务框架Dubbo,第1张

高性能服务框架Dubbo 一 Dubbo 概述

 

1.1Dubbo 介绍

Dubbo是阿里巴巴公司开源的一个高性能、轻量级的 Java RPC 框架。

致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。

2011年10月27日,阿里巴巴开源了自己的SOA服务化治理方案的核心框架Dubbo

2012年10月23日Dubbo2.5.3发布后,在Dubbo开源将满一周年之际,阿里基本停止了对Dubbo的主要升级。只在之后的2013年和2014年更新过2次对Dubbo2.4的维护版本,然后停止了所有维护工作。Dubbo对Spring 的支持也停留在了Spring 2.5.6版本。

阿里停止维护和升级Dubbo期间,当当网开始维护自己的Dubbo分支版本Dubbox,支持了新版本的Spring,并对外开源了Dubbox。同时,网易考拉也维护了自己的独立分支Dubbok,可惜并未对外开源。

随着微服务的火热兴起,在国内外开发者对阿里不再升级维护Dubbo的吐槽声中,阿里终于开始重新对Dubbo的升级和维护工作。在2017年9月7日,阿里发布了Dubbo的2.5.4版本,距离上一个版本2.5.3发布已经接近快5年时间了。在随后的几个月中,阿里Dubbo开发团队以差不多每月一版本的速度开始快速升级迭代,修补了Dubbo老版本多年来存在的诸多bug,并对Spring等组件的支持进行了全面升级。

2018年1月8日,Dubbo2.6.0版本发布,并将之前当当网开源的Dubbo分支Dubbox进行了合并,实现了Dubbo版本的统一整合。

官网:http://dubbo.apache.org

 

1.2架构 节点角色说明Provider暴露服务的服务提供方Consumer调用远程服务的服务消费方Registry服务注册与发现的注册中心Monitor统计服务的调用次数和调用时间的监控中心Container服务运行容器

 

 

二 Dubbo 快速入门 2.1 zookeeper安装

Dubbo默认支持五种注册中心:推荐使用 Zookeeper 注册中心

Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用。

安装步骤 :

1)上传jdk安装包jdk-8u171-linux-x64.tar.gz到linux系统并解压

# 进入/usr/local 目录
cd /usr/local 
tar -zxvf jdk-8u171-linux-x64.tar.gz

2)设置环境变量:

vi /etc/profile
JAVA_HOME=/usr/local/jdk1.8.0_171
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_HOME
export PATH
export CLASSPATH

3)使得环境变量生效

source /etc/profile

4)验证

java -version

5)安装zk

# 进入/usr/local
cd /usr/local
# 把压缩包上传到linux系统,解压
tar -zxvf zookeeper-3.4.6.tar.gz 	
# 进入zookeeper-3.4.6目录
cd zookeeper-3.4.6	

# 进入conf目录
cd conf	

# 把zoo_sample.cfg 改名为 zoo.cfg
mv zoo_sample.cfg zoo.cfg	

# 打开zoo.cfg文件, 修改dataDir属性
vi zoo.cfg	

 

# 设置zoo.cfg放置数据的目录
dataDir=/usr/local/zookeeper-3.4.6/data
# wq保存退出
./zkServer.sh stop						# 停止服务 
./zkServer.sh status    				# 查看服务状态
2.2 服务提供者

实现步骤

1)创建maven工程:dubbo-service-user,添加依赖



    4.0.0

    
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.6.RELEASE
    

    cn.itcast
    dubbo-service-user
    1.0-SNAPSHOT

    
         
        
            org.springframework.boot
            spring-boot-starter-web
        

        
        
            org.apache.dubbo
            dubbo-spring-boot-starter
            2.7.5
        
        
        
        
            org.apache.curator
            curator-recipes
            4.2.0
        
        
        
        
            org.apache.zookeeper
            zookeeper
            3.4.6
        

    

 注意事项:如果出现zookeeper not connected主要是 jdk版本和zookeeper版本不匹配,jdk1.8以后,pom中zookeeper依赖不能超过3.4+,不然就会报错。此外3.3+的版本依赖包阿里云中没有,所以建议使用3.4+版本的。

2)创建application.yml配置文件,并添加配置如下

# springboot项目对外暴漏的端口(web项目就是访问端口)
server:
  port: 9001

dubbo:
  application:
    # 项目名称,用于计算服务的依赖关系。(区分不同项目的服务)
    name: dubbo-service-user
  # 指定zk注册中心地址
  registry:
    address: zookeeper://192.168.12.134:2181
  protocol:
    # 对外暴漏的服务使用的协议:dubbo协议, 官网推荐
    name: dubbo
    # 对外暴漏服务的端口
    port: 20881
  # dubbo包扫描,会扫描dubbo提供的@Service注解
  scan:
    base-packages: cn.itcast.api

3)编写Api接口

package cn.itcast.api;


public interface UserApi {
    String sayHi(String name);
}

4)编写Api接口实现类

package cn.itcast.api.impl;

import cn.itcast.api.UserApi;
import org.apache.dubbo.config.annotation.Service;  


@Service
public class UserApiImpl implements UserApi {
    
    @Override
    public String sayHi(String name) {
        return "hi," + name;
    }
}

5)启动类

package cn.itcast;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

启动后的执行流程:

1、Spring容器启动

2、Dubbo自动配置类开始执行

3、读取yml中相关配置,扫描包路径:cn.itcast.api

4、找到加了@Service注解的实现类:UserApiImpl

5、将UserApiImpl作为一个提供的服务接口放到zk中,指定使用dubbo协议,20881端口,key为cn.itcast.api.UserApi,

value: dubbo://localhost:20881/userApiImpl

2.3 服务消费者



    4.0.0

    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.6.RELEASE
    

    cn.itcast
    order-web-manager
    1.0-SNAPSHOT

    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
        
            org.apache.dubbo
            dubbo-spring-boot-starter
            2.7.5
        
        
        
        
            org.apache.curator
            curator-recipes
            4.2.0
        
        
        
        
            org.apache.zookeeper
            zookeeper
            3.4.6
        
    

2)编写application.yml  

server:
  port: 8080
dubbo:
  # 项目名称,用于计算服务的依赖关系。(区分不同项目的服务)
  application:
    name: order-web-manager
  # 注册中心地址
  registry:
    address: zookeeper://192.168.12.134:2181

3)编写api接口

注意:服务消费者的接口名称、接口方法名称、包路径必须要与服务提供者一致,否则生成代理对象调用报错。

所以:这里的接口最好从服务提供者那里拷贝,不要手动去编写。

package cn.itcast.api;


public interface UserApi {
    String sayHi(String name);
}

4)编写控制器

package cn.itcast.controller;

import cn.itcast.api.UserApi;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("order")
public class OrderController {

    
    @Reference
    private UserApi userApi;

    @GetMapping
    public String hello(){
        // 执行RPC远程调用, 获取dubbo服务返回结果. 在浏览器显示
        String result = userApi.sayHi("Tom");
        return result;
    }
}

5)启动类

package cn.itcast;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

6)访问http://localhost:8080/order

执行流程:

1、Spring容器启动

2、Dubbo自动配置类开始执行,加载相关配置。

3、初始化OrderController时,发现有个属性加了@Reference注解,处理该属性

4、根据加载的相关配置,从zk中获取已经注册上去的信息,生成代理对象,并设置到OrderController的属性中。

5、调用hello方法时,执行RPC远程调用服务提供端,得到返回结果。

2.4. 优化项目结构

创建Api接口工程:dubbo-service-api,抽取接口UserApi,将其放入dubbo-service-api

package cn.itcast.api;

public interface UserApi {
    String sayHi(String name);
}

2)优化服务提供者

dubbo-service-user 工程删除UserApi, 然后添加依赖:


    cn.itcast
    dubbo-service-api
    1.0-SNAPSHOT

3)优化服务消费者

order-web-manager 工程删除UserApi, 然后添加依赖:


    cn.itcast
    dubbo-service-api
    1.0-SNAPSHOT
三 Dubbo-admin 管理平台(了解) 3.1介绍

我们在开发时,需要知道Zookeeper注册中心都注册了哪些服务,有哪些消费者来消费这些服务。我们可以通过部署一个管理中心来实现。其实管理中心就是一个web应用,部署到tomcat即可。

3.2 安装

安装步骤如下:

1)将资料中的dubbo-admin-2.6.0.war文件复制到tomcat的webapps目录下

2)启动tomcat,此war文件会自动解压。 注意:Tomcat不要放到中文目录!!!

3)修改WEB-INF下的dubbo.properties文件,注意dubbo.registry.address对应的值需要对应当前使用的Zookeeper的ip地址和端口号

dubbo.registry.address=zookeeper://192.168.134.129:2181  
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest

4)重启tomcat

3.3 使用

*** 作步骤:

1)访问http://localhost:6080/dubbo-admin-2.6.0/,输入用户名(root)和密码(root)

2)启动服务提供者工程和服务消费者工程,可以在查看到对应的信息

四  Dubbo 高级特性(重点) 4.1 序列化

在订单服务中,需要查询用户信息。现在需要在dubbo服务提供者中添加一个根据用户id查询用户的方法,并交给订单系统远程调用。这里需要注意:dubbo服务提供端与消费端之间传递的对象,必须要实现序列化接口。

4.1.2 dubbo-service-api 接口工程

1)创建实体类,注意: 这里的实体类必须实现序列化接口,否则报错。

package cn.itcast.pojo;

import java.io.Serializable;


public class User implements Serializable {

    private Long id;

    private String name;

    private Integer age;

    private Integer sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

2)编写接口,在接口添加一个方法:findById()

package cn.itcast.api;

import cn.itcast.pojo.User;

public interface UserApi {
    String sayHi(String name);
    User findById(Long id);
}

4.1.3 dubbo-service-user服务工程

1)改造UserApiImpl

package cn.itcast.api.impl;

import cn.itcast.api.UserApi;
import cn.itcast.pojo.User;
import org.apache.dubbo.config.annotation.Service;


@Service
public class UserApiImpl implements UserApi {

    @Override
    public User findById(Long id) {
        User user = new User();
        user.setId(1l);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }

    @Override
    public String sayHi(String name) {
        return "hello, " + name;
    }
}

2)重启服务

4.1.4 order-web-manager消费者工程

1)改造UserApiImpl

package cn.itcast.api.impl;

import cn.itcast.api.UserApi;
import cn.itcast.pojo.User;
import org.apache.dubbo.config.annotation.Service;


@Service
public class UserApiImpl implements UserApi {

    @Override
    public User findById(Long id) {
        User user = new User();
        user.setId(1l);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }

    @Override
    public String sayHi(String name) {
        return "hello, " + name;
    }
}

2)重启服务

6.1.4 order-web-manager消费者工程

1)修改控制器

package cn.itcast.controller;

import cn.itcast.api.UserApi;
import cn.itcast.pojo.User;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("order")
public class OrderController {

    
    @Reference
    private UserApi userApi;

    
    @GetMapping("/user/{id}")
    public User findUserById(@PathVariable("id") Long id){
        User user = userApi.findById(id);
        return user;
    }

    @GetMapping
    public String hello(){
        // 执行RPC远程调用, 获取dubbo服务返回结果, 在浏览器显示
        String result = userApi.sayHi("Tom");
        return result;
    }
}

2)重启服务,访问http://localhost:8080/order/user/1

4.1.5 无序列化报错示例

cause:java.lang.IllegalStateException: Serialized class cn.itcast.pojo.User must implement java.io.Serializable
4.2 地址缓存

4.2.1 介绍

 

提问:注册中心挂了,服务是否可以正常访问?

可以,因为dubbo服务消费者在第一次调用时,会将服务提供方地址缓存到本地,以后在调用则不会访问注册中心。

当服务提供者地址发生变化时,注册中心会通知服务消费者。

 

4.2.2 演示步骤

1)执行命令,关闭注册中心  

[root@itcast bin]# ./zkServer.sh stop

2)测试访问order服务,依然可以调用服务

 

4.3 超时与重试

4.3.1 介绍

 

 

服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一直等待下去,相关线程得不到释放。

在某个峰值时刻,大量的请求都在同时请求服务消费者,会造成线程的大量堆积,势必会造成雪崩。

dubbo 利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。 使用timeout属性配置超时时间,默认值1000,单位毫秒。

 

 

设置了超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。

如果出现网络延迟,则这一次请求就会失败。

Dubbo 提供重试机制来避免类似问题的发生。

通过 retries 属性来设置重试次数。默认为 2 次。

 

4.3.2 演示步骤

1)重启zk(之前关闭了)

2)服务提供端dubbo-service-user 中添加睡眠时间,再重启该服务

package cn.itcast.api.impl;

import cn.itcast.api.UserApi;
import cn.itcast.pojo.User;
import org.apache.dubbo.config.annotation.Service;


@Service
public class UserApiImpl implements UserApi {

    @Override
    public User findById(Long id) {
        User user = new User();
        user.setId(id);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }

    @Override
    public String sayHi(String name) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("111");
        return "hello, " + name;
    }
}

3)重启服务消费端 order-web-manager

4)调用http://localhost:9002/hello,发现报错

5)服务提供端dubbo-service-user 服务提供端添加超时、重试配置

package cn.itcast.api.impl;

import cn.itcast.api.UserApi;
import cn.itcast.pojo.User;
import org.apache.dubbo.config.annotation.Service;


@Service(timeout = 30000, retries = 0) // 设置超时时间(默认1000),重试次数(默认2次)
public class UserApiImpl implements UserApi {

    @Override
    public User findById(Long id) {
        User user = new User();
        user.setId(id);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }

    @Override
    public String sayHi(String name) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("111");
        return "hello, " + name;
    }
}

6)依次重启服务提供端、服务消费端,继续访问发现可以访问成功了。

注意事项

1)Debug时设置超时时间大一点,否则容易超时,因为debug中间停了下来。

2)Debug时重试次数设置为0次。

3)在服务提供端的@Service注解以及服务调用方的@Reference注解上都可以添加超时、重试配置(都加了以调用方为主)。

4)建议配置添加在服务提供端。

4.4 多版本

4.4.1 介绍

 

4.4.2 演示步骤

演示:启动2次服务,同时指定版本。消费者可以根据版本调用新老服务。

1)修改dubbo-service-user 工程的UserApiImpl

@Service(version = "1.0") // version指定服务版本
public class UserApiImpl implements UserApi {

    @Override
    public User findById(Long id) {
       	System.out.println("UserApiImpl服务版本1.0");
        User user = new User();
        user.setId(id);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }
}

2)修改dubbo-service-user中的application.yml配置

server:
  port: ${port:9001}   # 表示端口默认为9001;如果运行时期通过VM Option传入port参数,以传入为主。

dubbo:
  application:
    name: dubbo-service-user
  protocol:
    name: dubbo
    port: ${dport:20881} # 表示端口默认为20881;dport是动态传入的参数名称,可以随意定义
  registry:
    address: zookeeper://192.168.12.134:2181
  scan:
    base-packages: cn.itcast.api

3)启动dubbo-service-user工程,直接运行run方法即可(基于1.0版本代码)。

4)再次修改实现类,并指定版本与提示信息。

@Service(version = "2.0") // version指定服务版本
public class UserApiImpl implements UserApi {

    @Override
    public User findById(Long id) {
        System.out.println("UserApiImpl服务版本2.0");
        User user = new User();
        user.setId(id);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }
}

5)再次启动dubbo-service-user工程(基于2.0版本代码),注意:不要直接启动。直接启动没法传入port、dport两个参数,会报端口冲突的错误。启动前先修改VM Options参数:

 启动后服务列表如下:

 6)最后,消费者通过版本号来调用指定版本服务提供者(实际项目中可以将消费者做集群,部分服务去调用提供者1.0版本,部分服务去调用提供者2.0版本)

@RestController
@RequestMapping("order")
public class OrderController {
    
    // @Reference(version = "1.0")
    @Reference(version = "2.0")  // 修改版本后重启
    private UserApi userApi;

    
    @GetMapping("/user/{id}")
    public User findById(@PathVariable("id") Long id){
        return userApi.findById(id);
    }
}

7)测试,访问服务消费者,发现在9002(即2.0版本)的控制台中打印了文字,说明被调用了。

4.5 负载均衡

4.5.1 介绍

问题:当服务提供者搭建集群时,我们该调用哪个服务呢?这就需要负载均衡

负载均衡策略(4种):

random :按权重随机,默认值。按权重设置随机概率。

roundrobin :按权重轮询。

leastactive:最少活跃调用数,相同活跃数的随机。

consistenthash:一致性 Hash,相同参数的请求总是发到同一提供者。

演示:准备二个服务提供端,权重分别是100/200,测试负载均衡策略。本例使用random随机。

4.5.2 服务提供者一

1)设置权重 weight = 100

 

@Service(weight = 100)
public class UserApiImpl implements UserApi {
    
    @Override
    public User findById(Long id) {

        System.out.println("服务提供端1:权重100");
        User user = new User();
        user.setId(id);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }
    ...
}

2)重启服务

 

4.5.2 服务提供者二

1)重新修改服务提供者UserApiImpl,设置权重weight = 200

@Service(weight = 200)
public class UserApiImpl implements UserApi {
    
    
    @Override
    public User findById(Long id) {

        System.out.println("服务提供端2:权重200");
        User user = new User();
        user.setId(id);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }
    ...
}

 2)启动服务启动者2: VM Option 需要配置 -Dport=9002 -Ddport=20882 (多版本时候已经配了)。

4.5.4 服务消费者

@RestController
@RequestMapping("order")
public class OrderController {

    @Reference(loadbalance = "random") // 按照权重随机
    private UserApi userApi;

    
    @GetMapping("/user/{id}")
    public User findById(@PathVariable("id") Long id){
        return userApi.findById(id);
    }
}

 

访问 http://localhost:8080/order/user/1 10次,运行结果如下,提供端2打印了6次,提供端1打印了4次,发现调用到提供端2的次数多一些(不一定是2:1,但调用非常多次时,大概是2:1的比例)

服务提供者1:

服务提供者2:

 说明:负载均衡算法设置同样可以添加在提供端,建议加在消费端

4.6 集群容错

集群容错模式:

 

Failover Cluster:失败重试。默认值。当出现失败,重试其它服务器 ,默认重试2次,使用 retries 配置。一般用于读 *** 作

Failfast Cluster :快速失败,只发起一次调用,失败立即报错。通常用于写 *** 作。(不重试)

Failsafe Cluster :失败安全,出现异常时,直接忽略。返回一个空结果。(一般用于不太重要的 *** 作,比如消息通知)

Failback Cluster :失败自动恢复,后台记录失败请求,定时重发。(一般用于非常重要的 *** 作)

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

Broadcast Cluster :广播调用所有提供者,逐个调用,任意一台报错则报错。

 

4.6.2 案例描述

测试集群容错模式:Failover Cluster:失败重试。

需求:

1)准备两个服务提供者,第一个的实现类中设置线程睡眠时间,模拟超时调用失败。第二个实现类中不设置睡眠时间。

2)如果来自消费者的请求第一次调用了第一个服务提供者会超时,自动进行失败重试,进行重试,可能找到第一个,也可能找到第二个,如果找到的还是第一个,又会重试。

3)如果来自消费者的请求第一次调用了第二个服务提供者,那直接成功了,不会有后续 *** 作了。

6.6.3 演示步骤

 1) 修改服务提供者一,然后重启

@Service
public class UserApiImpl implements UserApi {

    @Override
    public User findById(Long id) {
        System.out.println("服务提供端1");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        User user = new User();
        user.setId(id);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }
    ...
}

2)修改服务提供者二,然后重启

@Service
public class UserApiImpl implements UserApi {
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public User findById(Long id) {
        System.out.println("服务提供端2");
        User user = new User();
        user.setId(id);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }
    ...
}

3)修改服务消费者集群容错模式为failover,失败重试

@RestController
@RequestMapping("order")
public class OrderController {

    @Reference(cluster = "failover")
    private UserApi userApi;

    
    @GetMapping("/user/{id}")
    public User findById(@PathVariable("id") Long id){
        return userApi.findById(id);
    }
}

4)测试,访问http://localhost:8080/order/user/1

查看控制台,可以发现它最开始可能是调用9001或9002,然后超时了进行重试,可能接下来继续调用9002,也可能9001,如果再调不通,又会重试一次。

4.7 服务降级

4.6.1 介绍

当服务因为某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放出服务器资源,增加响应速度!

当下游的服务因为某种原因响应超时或不可用,上游主动调用本地的一些降级逻辑,避免等待或出错,迅速返回给用户!

参考官网:服务降级 | Apache Dubbo

降级 Dubbo 服务:可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。

其中:

mock=force:return null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。

mock=fail:return null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

4.6.2 演示

演示1: mock=force:return null

测试后发现:dubbo服务提供端控制台没有任何输出,且服务消费端没有报错,说明服务被降级了,没有调用服务提供端。

 

@RestController
@RequestMapping("order")
public class OrderController {

    // 表示不发起远程调用,直接返回null
    @Reference(mock = "force:return null")
    private UserApi userApi;

}

演示2:mock=fail:return null

@Service
public class UserApiImpl implements UserApi {

    @Override
    public User findById(Long id) {
        System.out.println("服务提供端2");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        User user = new User();
        user.setId(1l);
        user.setName("张三");
        user.setAge(20);
        user.setSex(1);
        return user;
    }
}

步骤2:服务的方法调用超时后,再返回 null 值,不抛异常

@RestController
@RequestMapping("order")
public class OrderController {

    // 服务的方法调用在失败后,再返回 null 值,不抛异常
    @Reference(mock = "fail:return null")
    private UserApi userApi;

}

步骤3:访问测试

因为调用服务超时,自动重试2次。最终调用服务失败,返回null

五  面试题(重点)

问题1: Dubbo只能从注册中心获取服务吗?

不是,也可以使用直连,直连方式是不需要从注册中心获取服务。
在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时可能需要点对点直连方式。

@Reference(url = "dubbo://localhost:24567")
private IUserservice userservice;

直连方式会失去负载均衡的能力,所以不适合生产环境。

问题2: Dubbo服务提供者一定要需要先开启动,消费者后启动吗?

不需要,如果在@Reference中添加check=false,可以先启动消费者,再启动提供者 

 问题3: Dubbo默认调用服务超时时长是多少?

服务超时时长是: 1000毫秒

 问题4: Dubbo集群容错模式有哪些? 默认容错模式是什么?

Dubbo集群容错模式有6种: 
Failover(失败重试、读 *** 作)
Failfast(快速失败、写 *** 作、不重试)
Failsafe(失败安全,忽略本次失败的请求)
Failback(失败自动恢复,记录失败请求,定时重发)
Forking(并行调用每个服务提供者,只要一个成功就返回)
Broadcast(广播模式,逐个调用,任意一个报错就报错)
默认容错模式是: Failover(失败重试)

 问题5: Dubbo注册中心有哪些?

Dubbo默认支持五种注册中心:
1. Multicast
2. Zookeeper(推荐)
3. Nacos
4. Redis
5. Simple

 问题6: Dubbo注册中心zookeeper挂掉,消费者还可以正常调用服务提供者吗?

可以正常调用,因为消费者从注册中心,获取服务地址后会在本地缓存。(地址缓存)

 问题7: Dubbo如何实现服务降级?

心如死灰了, 不发起远程调用,直接返回null值。
mock=force:return null

在远程调用失败后,返回null值,对消费者不产生调用影响。
mock=fail:return null

 问题8: Dubbo负载均衡策略有哪些,默认负载均衡策略是什么?

负载均衡策略有4种:
1. random(随机,按照权重随机,相当于翻牌子)
2. roundrobin(轮询,按照权重逐个调用,挨个来)
3. leastactive(最少活跃数,性能好的机器能处理更多的请求)
4. consistanthash(一致性hash,相同参数的请求都发给同一个)

默认负载均衡策略是: random (随机)

 问题9: Dubbo项目灰度发布?

使用服务提供者的版本号隔离,调用时指定版本号。 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5700772.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存