1.Dubbo的基本应用与高级应用

85 阅读6分钟

负载均衡策略

官网地址

dubbo.apache.org/zh/docs/v2.…

策略分类

① Random

随机,按照权重设置随机的概率。

② RoundRobin

轮询,按公约后的权重设置轮询比率。存在慢的提供者堆积请求的问题。

③ LeastActive

最少活越调用数,让慢的提供者收到更少的请求,相同活跃数的提供者随机。

最小活跃数怎样统计?

按照正常逻辑,最小活跃数应该由提供者统计,统计正在执行中的请求数,但是Dubbo是由消费者进行统计的,具体的步骤:

  • 消费者会缓存所有的服务提供者,比如记为P1、P2、P3,并且每个服务提供者内都有一个属性:active,默认值为0
  • 消费者调用提供者时,如果负载均衡策略是leastactive,消费者会从缓存的所有的提供者中找到最小的active,如果相同则随机。
  • 比如找到的为P2提供者,则将P2.active+1
  • 比如找到的为P2提供者,则将P2.active+1
  • 消费端收到请求之后,再将P2.active-1,这样就完成了调用

④ ConsistentHash

一致性hash,相同参数的请求总是发送到同一个提供者。如果这个提供者挂掉,就会基于一个虚拟节点,将请求平摊给其他的提供者,不会引起剧烈变动。

配置

提供者和消费者都可以配置负载均衡策略,如果都配置了,以消费者为准。

dubbo: 
   consumer: 
        loadbalance: roundrobin 
   provider: 
        loadbalance: consistenthash

服务超时

在服务消费者和服务提供者上都可以配置服务超时时间,这两者是不一样的。 消费者调用提供者的服务,分为3步:

  • 消费者发送请求(网络传输)
  • 服务端执行服务
  • 服务端返回响应(网络传输)

只在消费端或服务端二者其一配置

这种表示消费端调用服务的超时时间。如果超时,消费端会抛出异常,但服务端不会抛异常,服务端在执行完成后,会检查该服务的时间,如果超过timeout,则会打印一个超时日志。

消费端和服务端同时配置

假设服务执行用时4S,服务端超时时间为6s,消费端超时时间为3s....

在调用服务时,消费端会收到超时异常,服务端一切正常。

假设服务执行用时4S,服务端超时时间为3s,消费端超时时间为6s....

服务正常返回,服务端和消费端都不会出现异常。

配置

// 1.注解上配置 
@Reference(timeout = 7000) 
// 2.配置文件配置 
dubbo: 
   consumer: 
     timeout: 3000

集群容错

官网地址

dubbo.apache.org/zh/docs/v2.…

什么是集群容错

消费者在调用某个服务时,这个服务有多个提供者,在经过负载均衡后选出其中一个提供者进行调用,但调用报错后,Dubbo采取的后续处理策略。

集群容错的分类

Dubbo一共提供了六种集群容错策略,可以根据具体的场景进行选择。

① Failover(默认)

失败自动切换,当调用失败时,重试其他服务器。通常用于读操作,但重试会带来更长的延迟时间,如果设置的延迟时间不足,消费端会报超时错误。

失败重试:Dubbo默认的重试次数为2,即:一共调用3次。手动配置重试次数:

// 1.配置文件配置 
dubbo: 
   consumer: 
         timeout: 3000 
         retries: 5 
// 2.注解配置 
@Reference(retries = 3)

② Failfast

快速失败模式,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,例如:新增记录。

// 消费端配置 
@Reference(timeout = 7000,cluster = "failfast") 
ProviderServiceInterface providerService;

③ Failsafe

失败安全,出现异常时,直接忽略。通常用于审计日志等操作。

④ Failback

失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

⑤ Forking

并行调用多个服务器,只要有一个返回就算成功。通常用于实时性较高的读操作,但是浪费资源,可以通过“forks=2”来设置最大并行数。

⑥ Broadcast

广播调用所有的提供者,只要有一个报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。

服务降级

官网地址

dubbo.apache.org/zh/docs/v2.…

什么是服务降级

在消费者调用提供者服务时,由于各种原因导致调用失败(服务器泵机、网络超时等),可以返回默认值,避免影响主业务流程。

服务降级的两种方式

Dubbo的服务降级采用的是Mock机制,具有两种降级处理方式:Mock null,Mock Class。

Mock null降级处理

出现异常时,将异常忽略,返回设置的默认值。
在服务降级时会对提供者中的所有方法进行统一处理,返回指定的默认值。例如:提供者泵机,所有方法都返回统一的默认值。

@Reference(mock = "return null") 
ProviderServiceInterface providerService;

Mock Class降级处理

Mock null是对所有的方法进行统一处理,但是有时候一些方法不可用时需要提示我们做出响应的处理,所以需要对提供的所有方法进行区分,Mock Class就能满足这种需求。
1. 在接口的同级目录下,创建一个类,类名为:接口名+Mock

public class ProviderServiceInterfaceMock implements ProviderServiceInterface {
    @Override
    public String getServerPort() {
        // 具体的出错后的业务处理
        return "提供者服务调用出错";
    }
    @Override
    public String sayHello() {
        // 具体的出错后的业务处理
        return "提供者服务调用出错";
    }
}

2.消费者设置mock = "true"

@Reference(mock = "true") 
ProviderServiceInterface providerService;

集群容错和服务降级的区别

  • 集群容错时整个集群范围内的容错
  • 服务降级是单个服务提供者的自身容错

本地存根

官网地址

什么是本地存根?

在RPC调用过程中,客户端(即消费者)只持有接口,服务端(即生产者)持有的是接口的具体实现。有些时候,想要在客户端执行部分逻辑:做ThreadLocal缓存、参数验证、调用失败后伪造容错数据等等,此时就需要用到本地存根。

本地存根就是对服务端的代理,在代理内可以做响应的操作。

实现方式

1. 在接口的同级目录下,创建一个类,类名为:接口名+Stub
需要注意的是:类中需要有一个构造方法,传入咱们真正调用的接口,真正的是哪个接口,由Dubbo框架实现

public class ProviderServiceInterfaceStub implements ProviderServiceInterface {

    ProviderServiceInterface providerService;
    // 构造函数传入真正的远程代理对象
    public ProviderServiceInterfaceStub(ProviderServiceInterface providerService){
        this.providerService=providerService;
    }

    @Override
    public String getServerPort() {
        System.out.println("服务存根");
        return providerService.getServerPort();
    }
    @Override
    public String sayHello() {
        System.out.println("服务存根");
        return providerService.sayHello();
    }
}

2. 消费者设置stub = "true"

@Reference(stub = "true") 
ProviderServiceInterface providerService;

思考:服务降级和本地存根怎样配合使用?

首先我们得搞清楚服务降级和本地存根的作用:

  • 服务降级:就是在服务调用失败时,返回默认数据。
  • 服务存根:使用一个代理,在代理内增强提供者。 我们不能在提供者中去处理异常,应该把异常抛到代理类,在代理类中处理异常,这样就能触发到***Mock类中的默认数据。