likes
comments
collection
share

Dubbo的高级特性:服务治理篇

作者站长头像
站长
· 阅读数 30

王有志,一个分享硬核Java技术的互金摸鱼侠 加入Java人的提桶跑路群共同富裕的Java人

上一篇中,我们已经在Spring Boot应用中集成了Dubbo,并注册了一个服务提供方和一个服务使用方。当然,生产环境中应用往往会部署多个节点,以此来保证服务的高可用,那么如何配置Dubbo的负载均衡策略呢?

下面我们以此为切入点,来介绍Dubbo在服务治理方面提供的高级特性的配置与使用。Dubbo默认支持6种配置来源:

  • JVM System Properties,JVM-D参数
  • System environment,JVM进程的环境变量
  • Externalized Configuration,外部化配置,从配置中心读取
  • Application Configuration,应用的属性配置,从Spring应用的Environment中提取"dubbo"打头的属性集
  • API/XML/注解等编程接口采集的配置可以被理解成配置来源的一种,是直接面向用户编程的配置采集方式
  • 从classpath读取配置文件 dubbo.properties

不过在今天的内容中,我们只会涉及到Application Configuration,XML和注解这3种常见的配置方式。

Tips:本篇为基础内容,重点在配置和使用,不涉及任何实现原理和算法原理。

负载均衡

微服务中,负载均衡指的是将请求“合理”的分配在服务的不同节点间,以达到优化使用资源,提供高吞吐量,降低响应时间的目的。Dubbo 3.X中提供了7种负载均衡策略:

算法特性配置值默认配置说明
Weighted Random LoadBalance加权随机random默认算法,默认权重相同
RoundRobin LoadBalance加权轮询roundrobin借鉴于 Nginx 的平滑加权轮询算法,默认权重相同,
LeastActive LoadBalance最少活跃优先 + 加权随机leastactive背后是能者多劳的思想
Shortest-Response LoadBalance最短响应优先 + 加权随机shortestresponse更加关注响应速度
ConsistentHash LoadBalance一致性哈希consistenthash确定的入参,确定的提供者,适用于有状态请求
P2C LoadBalancePower of Two Choicep2c随机选择两个节点后,继续选择“连接数”较小的那个节点。
Adaptive LoadBalance自适应负载均衡adaptive在 P2C 算法基础上,选择二者中 load 最小的那个节点

Dubbo支持为服务提供方和服务使用方配置负载均衡策略,当两者都配置了负载均衡策略,以服务使用方的负载均衡策略为准。

首先我们来看XML文件的配置方式,通过XML文件,可以为接口,方法配置负载均衡策略,先为服务提供方的DubboDemoService接口配置负载均衡策略:

<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl" loadbalance="roundrobin"/>

接着我们为服务使用方在调用DubboDemoService#say方法时配置负载均很策略:

<dubbo:reference id="DubboDemoService" interface="com.wyz.api.DubboDemoService">
  <dubbo:method name="say" loadbalance="roundrobin"/>
</dubbo:reference>

接着我们使用Application文件配置负载均衡策略,通过Application文件,可以配置Dubbo应用的全局负载均衡策略,内容如下:

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

最后注解的形式配置负载均衡策略,可以为接口和方法配置负载均衡策略配置,代码如下:

@DubboService(loadbalance = "roundrobin")
public class DubboDemoServiceImpl implements DubboDemoService {
  
  @Override
  @DubboService(loadbalance = "leastactive")
  public String say(String message) {
    return "DubboProvider  say : " + message;
  }
}

集群容错

当配置好负载均衡策略后,程序一直稳定运行。可是突然有一天,集群中的某个节点不可用了,当请求“命中”了不可用的节点后,Dubbo会如何处理呢?

Dubbo提供了集群容错的能力,实现了9中针对集群中节点故障的处理方案:

策略配置值默认配置特性应用场景
Failover Clusterfailover失败自动切换,当出现失败,重试其它服务器通常用于读操作,可以配置重试次数
Failfast Clusterfailfast快速失败,失败后立即报错通常用于非幂等写操作
Failsafe Clusterfailsafe失败安全,出现异常时,直接忽略通常用于写入审计日志
Failback Clusterfailback失败自动恢复,后台记录失败请求,定时重发通常用于消息通知
Forking Clusterforking并行调用多个服务器,只要一个成功即返回通常用于实时性要求较高的读操作
Broadcast Clusterbroadcast广播调用所有提供者,逐个调用,任意一台报错则报错缓存更新
Available Clusteravailable调用目前可用的实例(只调用一个),如果当前没有可用的实例,则抛出异常不需要负载均衡的场景
Mergeable Clustermergeable将集群中的调用结果聚合起来返回结果,通常和group一起配合使用/
ZoneAware Cluster/多注册中心订阅的场景,注册中心集群间的负载均衡/

XML文件的形式依旧提供了接口及接口方法级别的集群容错策略配置

<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl" cluster="failover" retries="2"/>

其中retries是Failover Cluster策略的参数,设定了接口重试的次数(不含正常调用次数),例如,在上述配置中,正常调用失败后,至多会再调用两次。通过XML配置方法级别的集群容错策略与配置负载均衡策略一致,这里就不过多赘述了。

Application文件中可以配置全局的集群容错策略,内容如下:

dubbo:
  provider:
    cluster: failover
    retries: 2

最后是注解配置方式,依旧是通过@DubboService来配置接口和接口方法级别的集群容错策略,代码如下:

@DubboService(cluster = "failover", retries = 2)
public class DubboDemoServiceImpl implements DubboDemoService {
  
  @Override
  @DubboService(cluster = "failover", retries = 2)
  public String say(String message) {
    return "DubboProviderXML  say : " + message;
  }
}

服务降级

Dubbo自身提供的服务降级功能较为简陋,只提供了mock功能,如果想要体验功能完善的限流熔断等功能,可以使用Sentinel,Hystrix以及Resilience4j等Dubbo支持的专业的技术组件。由于Dubbo的服务降级功能较为简陋,这里只通过3种XML文件的配置方式了解服务降级的功能的配置即可。

配置方式一

<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl"  mock="true"/>

这种方式的配置中,需要在相同包下有类名 + Mock后缀的实现类,例如:DubboDemoServiceMock

public class DubboDemoServiceMock implements DubboDemoService {
  @Override
  public String say(String message) {
    return "服务出错了!";
  }
}

配置方式二

通过Mock类的全限名配置:

<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl"  mock="com.wyz.api.DubboDemoServiceMock"/>

配置方式三

使用Dubbo定义的表达式:mock="[fail|force]return|throw xxx"

  • [fail|force],默认值fail,表示调用失败后,或不进行方法调用直接强制执行mock方法;

  • return xxx,表示返回指定结果,需要符合接口的返回类型;

  • throw xxx,表示抛出指定异常。

我们举几个例子:

<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl"  mock="return fail"/>
<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl"  mock="force:return false"/>
<dubbo:service interface="com.wyz.api.DubboDemoService" ref="dubboDemoServiceImpl"  mock="fail:throw java.lang.NullPointException"/>

服务分组

允许通过分组的方式来区分同一个接口的不同实现方式。例如:为DubboXMLService接口添加两个不同的实现DubboXMLServiceImpl和NewDubboXMLServiceImpl。

public interface DubboXMLService {
  String say(String message);
}

public class DubboXMLServiceImpl implements DubboXMLService {
  @Override
  public String say(String message) {
    return "DubboProviderXML say : " + message;
  }
}

public class NewDubboXMLServiceImpl implements DubboXMLService {
  @Override
  public String say(String message) {
    return "NewDubboProviderXML say : " + message;
  }
}

首先是通过XML文件配置服务提供方:

<bean id="dubboXMLServiceImpl" class="com.wyz.service.impl.DubboXMLServiceImpl"/>
<dubbo:service interface="com.wyz.api.DubboXMLService" ref="dubboXMLServiceImpl" group="XML-Provider"/>

<bean id="newDubboXMLServiceImpl" class="com.wyz.service.impl.NewDubboXMLServiceImpl"/>
<dubbo:service interface="com.wyz.api.DubboXMLService" ref="newDubboXMLServiceImpl" group="New-XML-Provider"/>

接着来看服务使用方的配置:

<dubbo:reference id="dubboXMLService" interface="com.wyz.api.DubboXMLService" group="XML-Provider"/>
<dubbo:reference id="newDubboXMLService" interface="com.wyz.api.DubboXMLService" group="New-XML-Provider"/>

使用的话也非常简单,可以直接通过@Autowired方式注入不同分组的服务:

public class DubboConsumerXMLService implements CommandLineRunner {
  
  @Autowired
  DubboXMLService dubboXMLService;
  
  @Autowired
  DubboXMLService newDubboXMLService;
  
  @Override
  public void run(String... args) {
    String message = dubboXMLService.say("wyz");
    System.out.println(message);
    
    String newMessage = newDubboXMLService.say("wyz");
    System.out.println(newMessage);
  }
}

再来看如何通过注解的方式进行配置:

@DubboService(group = "Annotation-Provider")
public class DubboAnnotationServiceImpl implements DubboAnnotationService {
  @Override
  public String say(String message) {
    return "DubboProviderAnnotation say : " + message;
  }
}

@DubboService(group = "New-Annotation-Provider")
public class NewDubboAnnotationServiceImpl implements DubboAnnotationService {
  @Override
  public String say(String message) {
    return "NewDubboProviderAnnotation say : " + message;
  }
}

最后是通过注解使用不同分组的服务,注意这里要使用@DubboReference注入Bean:

@Component
public class DubboConsumerAnnotationService implements CommandLineRunner {
  
  @DubboReference(group = "Annotation-Provider")
  DubboAnnotationService dubboAnnotationService;
  
  @DubboReference(group = "New-Annotation-Provider")
  DubboAnnotationService newDubboAnnotationService;
  
  @Override
  public void run(String... args) {
    String message = dubboAnnotationService.say("wyz-Annotation");
    System.out.println(message);
    
    String newMessage = newDubboAnnotationService.say("wyz-Annotation");
    System.out.println(newMessage);
  }
}

Tips:不推荐通过Application文件的方式进行配置。

服务版本

Dubbo中,接口并不能唯一的确定一个服务,只有明确接口+分组+版本号才能唯一的确定一个服务,例如:

<dubbo:service interface="com.wyz.api.DubboXMLService" ref="dubboXMLServiceImpl" group="XML-Provider" version="1.0.0"/>

服务区分版本常见于版本发布验证的场景中,集群中部分节点升级服务,并切换少许流量,验证成功后,再大范围升级节点,可以降低服务升级带来的风险

服务版本的配置与使用方式与服务分组一样,这里只展示XML文件的配置方式:

<bean id="dubboXMLServiceImpl" class="com.wyz.service.impl.DubboXMLServiceImpl"/>
<dubbo:service interface="com.wyz.api.DubboXMLService" ref="dubboXMLServiceImpl" version="1.0.0"/>

服务使用者的XML文件配置:

<dubbo:reference id="dubboXMLService" interface="com.wyz.api.DubboXMLService" version="1.0.0"/>

XML文件的配置方式可以直接使用@Autowired注入不同版本的服务,我们这里就不赘述了。


今天,我们一起了解并学习了如何配置和使用Dubbo提供的服务治理的能力。

除了上面提到的服务治理能力外,Dubbo还提供了服务路由的能力,Dubbo 2.7之前,可以通过<dubbo:route>标签来配置路由规则,但在Dubbo 2.7之后,官方移除了<dubbo:route>标签,引入了一套依赖于注册中心和配置中心的全新路由配置机制,后面会出一篇番外篇,将注册中心迁移到Nacos上,并学习如何配置路由规则。

如果本文对你有帮助的话,还请多多点赞支持。如果文章中出现任何错误,还请批评指正。最后欢迎大家关注分享硬核技术的金融摸鱼侠王有志,我们下次再见!

转载自:https://juejin.cn/post/7254450297467945016
评论
请登录