一、负载均衡

随机(默认)、轮询、最少活跃、一致性哈希
消费端和服务端都可以配置负载均衡策略。都配置以消费端为准
https://dubbo.apache.org/zh/docs/v2.7/user/examples/loadbalance/

最少活跃数

正常情况下,最少活跃数应该是在服务提供者端进行统计的,服务提供者统计有多少个请求正在执行中。
为不影响服务端性能,Dubbo是在消费端进行统计的。(只能统计当前消费者请求情况,不会统计全局)

  1. 每个消费者会缓存所调用服务的所有提供者,比如p1、p2、p3三个服务提供者,每个提供者内对应一个active属性,默认位0
  2. 消费者在发起调用时,消费者端会选择active最小的服务提供者,如果都相同,则随机。
  3. 选出某一个服务提供者后,假设p2,Dubbo就会对p2.active+1
  4. 然后真正发起调用。
  5. 消费端收到响应结果后,进行p2.active-1
  6. 这样就完成了对某个服务提供者当前活跃调用数进行了统计,并且并不影响服务调用的性能。

    一致性哈希

    默认根据第一个参数计算hash,决定调用服务,参数相同时,会调用同一台服务

    二、服务超时

    服务提供者和服务消费者,都可以配置服务超时时间。都配置以消费端为准。

    消费者调用步骤

    1. 消费者发送请求(网络传输)
    2. 服务端执行业务处理
    3. 服务端返回响应(网络传输)

      超时分析

      服务端和消费端都配置超时时间

      • 服务执行为5s
      • 消费端timeout=3s
      • 服务端timeout=6s

消费端调用服务时,消费端会收到超时异常(因为消费端超时了),服务端一切正常(服务端没有超时)

三、集群容错

Failover Cluster(失败自动切换)【默认重试2次】
Failfast Cluster(快速失败)
Failsafe Cluster(失败安全)
Forking Cluster(并行调用多个服务提供者,一个成功即可)
Broadcast Cluster(广播所有服务提供者,必须都成功才成功)
官方文档很清晰。https://dubbo.apache.org/zh/docs/v2.7/user/examples/fault-tolerent-strategy/

四、服务降级

当非关键服务调用出错时,不抛异常,返回预定数据。 具体操作,可以看官方文档例子:https://dubbo.apache.org/zh/docs/v2.7/user/examples/service-downgrade/

  1. /**
  2. * mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
  3. * mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
  4. */
  5. @DubboReference(mock = "force:return null")
  6. //@DubboReference(mock = "fail:return null")
  7. private MockService mockService;

服务降级与集群容错区别

  1. 集群容错,针对的是整个集群,是整个集群范围内的容错
  2. 服务降级,是单个服务提供者自身的容错。(不会抛出异常,也不会触发集群容错)

    五、本地存根

    本质是一段在消费者端执行的逻辑,逻辑可以由服务提供者提供(也可以在消费端实现)。
    可以利用这种机制在消费者调用服务前(或后),做一些额外处理(类似装饰者模式,将原服务进行封装)
    实现类必须实现对应服务的接口。可以作为服务降级的一种处理方式
    官方文档例子:https://dubbo.apache.org/zh/docs/v2.7/user/examples/local-stub/ ```java @Component(“demoServiceComponent”) public class DemoServiceComponent implements DemoService {

    //默认查找接口所在包下的接口名+Stub的类:org.apache.dubbo.demo.DemoServiceStub //@DubboReference(stub = “true”) //指定实现类 @DubboReference(stub = “org.apache.dubbo.demo.consumer.comp.DemoServiceConsumerStub”) private DemoService demoService;

    @Override public String sayHello(String name) {

    1. return demoService.sayHello(name);

    } }

  1. ```java
  2. public class DemoServiceConsumerStub implements DemoService {
  3. private DemoService demoService;
  4. public DemoServiceConsumerStub(DemoService demoService) {
  5. this.demoService = demoService;
  6. }
  7. @Override
  8. public String sayHello(String name) {
  9. System.out.println("调用前处理逻辑");
  10. String sayHello = null;
  11. try {
  12. sayHello = demoService.sayHello(name);
  13. System.out.println("执行逻辑返回:"+sayHello);
  14. } catch (Exception e) {
  15. System.out.println("调用远程服务失败了。");
  16. }
  17. System.out.println("调用后处理逻辑");
  18. return sayHello;
  19. }
  20. }
  1. 调用前处理逻辑
  2. 执行逻辑返回:Hello world, response from provider: 192.168.1.4:20880
  3. 调用后处理逻辑

六、本地伪装

通常用于服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过 Mock 数据返回
授权失败。也可用于测试环境。
mock逻辑可以在消费端,也可以在提供端
官方示例:https://dubbo.apache.org/zh/docs/v2.7/user/examples/local-mock/

  1. @Component("demoServiceComponent")
  2. public class DemoServiceComponent implements DemoService {
  3. /**
  4. * mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
  5. * mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
  6. */
  7. //@DubboReference(mock = "force:return null")
  8. //@DubboReference(mock = "fail:return null")
  9. @DubboReference(mock = "force:org.apache.dubbo.demo.consumer.comp.MockServiceHandler")
  10. private MockService mockService;
  11. @Override
  12. public List<Integer> callMock(Integer integer) {
  13. List<Integer> call = mockService.call(integer);
  14. System.out.println("调用降级服务返回值:" + call);
  15. return call;
  16. }
  1. public class MockServiceHandler implements MockService {
  2. @Override
  3. public List<Integer> call(Integer integer) {
  4. System.out.println("执行mock服务");
  5. return Lists.newArrayList(991);
  6. }
  7. }
  1. 执行mock服务
  2. 调用降级服务返回值:[991]

七、参数回调

如果当前服务支持参数回调,即:对于服务接口中的某个方法,如果想支持消费者在调用这个方法时能设置回调逻辑,那么该方法就需要提供一个入参用来表示回调逻辑。
因为Dubbo协议是基于长连接的,所以消费端在两次调用同一个方法时想指定不同的回调逻辑,那么就需要在调用时在指定一定key进行区分。
个人认为,参数回调意义不大。如果想调用消费端,消费端提供对外接口即可
官方文档:https://dubbo.apache.org/zh/docs/v2.7/user/examples/callback-parameter/

  1. @Component("demoServiceComponent")
  2. public class DemoServiceComponent implements DemoService {
  3. @DubboReference
  4. private CallbackService callbackService;
  5. @Override
  6. public void callCallback(){
  7. callbackService.addListener("1", new CallbackListenerImpl());
  8. }
  9. }
  1. // 使用@Method指定用与回调的方法:addListener。
  2. // 使用@Argument指定下标为1的参数用于回调。
  3. // callbacks指定最大同时支持回调数
  4. @DubboService(methods = {@Method(name = "addListener",arguments = {@Argument(index = 1,callback = true)})},callbacks = 10)
  5. public class CallbackServiceImpl implements CallbackService {
  6. @Override
  7. public void addListener(String key, CallbackListener listener) {
  8. System.out.println("提供者:回调测试");
  9. listener.changed(getChanged(key)); // 发送变更通知
  10. }
  11. private String getChanged(String key) {
  12. return "Changed: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
  13. }
  14. }
  1. public class CallbackListenerImpl implements CallbackListener {
  2. @Override
  3. public void changed(String msg) {
  4. System.out.println("消费者被服务端调用了"+msg);
  5. }
  6. }
  1. 提供者输出
  2. 提供者:回调测试
  3. 消费者输出
  4. 消费者被服务端调用了Changed: 2022-10-29 21:46:54

八、异步调用

官方文档:https://dubbo.apache.org/zh/docs/v2.7/user/examples/async-call/

九、泛化调用

服务提供者未提供接口依赖的情况下,可以调用提供者服务。但是需要知道提供者接口规范
官方文档:https://dubbo.apache.org/zh/docs/v2.7/user/examples/generic-reference/

  1. @Component("demoServiceComponent")
  2. public class DemoServiceComponent implements DemoService {
  3. @DubboReference(id="demoService",interfaceName = "org.apache.dubbo.demo.DemoService",generic = true)
  4. private GenericService genericService;
  5. @Override
  6. public void callGenericService(){
  7. System.out.println("泛化调用");
  8. Object invoke = genericService.$invoke("sayHello", new String[]{"java.lang.String"}, new Object[]{"泛化调用"});
  9. System.out.println(invoke);
  10. }
  11. }

十、泛化服务

1.可以用于实现通用的mock服务;
2.对于消费者,在没有引入提供者接口情况下,可以进行调用服务。
3.对于提供者,可以不定义接口,实现服务暴露。
官方文档:https://dubbo.apache.org/zh/docs/v2.7/user/examples/generic-service/

  1. /**
  2. * 可以用于实现通用的mock服务
  3. * @Author:masterlu
  4. * @Date:2022/10/29 10:16 下午
  5. */
  6. @DubboService(interfaceName = "org.apache.dubbo.demo.DemoService",version = "generic")
  7. public class GenericServiceImpl implements GenericService {
  8. @Override
  9. public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException {
  10. if ("sayHello".equals(method)) {
  11. return "Welcome " + args[0];
  12. }
  13. }
  14. }

十一、Dubbo中的REST

REST也是Dubbo所支持的一种协议。
主要用于:没有使用Dubbo框架服务消费者,使用Dubbo服务提供的服务。
官方文档:https://dubbo.apache.org/zh/docs/v2.7/user/rest/
依赖注解坐标

  1. <!--rest 注解支持-->
  2. <dependency>
  3. <groupId>javax.ws.rs</groupId>
  4. <artifactId>javax.ws.rs-api</artifactId>
  5. </dependency>
  6. <!--rest 协议支持-->
  7. <dependency>
  8. <groupId>org.apache.dubbo</groupId>
  9. <artifactId>dubbo-rpc-rest</artifactId>
  10. </dependency>