Dubbo的配置(服务熔断,服务降级……)

发布于 2021-07-03  2.58k 次阅读


一,Dubbo的配置方式和覆盖策略

Dubbo的配置来源
默认有四种配置来源:
  • JVM System Properties,-D 参数
  • Externalized Configuration,外部化配置
  • ServiceConfig、ReferenceConfig 等编程接口采集的配置
  • 本地配置文件 dubbo.properties
他们的覆盖策略:
优先级:
JVM参数配置 >> xml配置 >> properties配置

编程配置方式:

1,Spring XML配置

例:
<!-- dubbo-provier.xml -->

  <dubbo:application name="demo-provider"/>

  <dubbo:config-center address="zookeeper://127.0.0.1:2181"/>

  <dubbo:registry address="zookeeper://127.0.0.1:2181" simplified="true"/>

  <dubbo:metadata-report address="redis://127.0.0.1:6379"/>

  <dubbo:protocol name="dubbo" port="20880"/>

  <bean id="demoService" class="org.apache.dubbo.samples.basic.impl.DemoServiceImpl"/>

  <dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService"/>
2,Spring Annotation配置
例:
  // AnnotationService服务实现
  @Service
  public class AnnotationServiceImpl implements AnnotationService {
      @Override
      public String sayHello(String name) {

          System.out.println("async provider received: " + name);

          return "annotation: hello, " + name;
      }
  }

 

  ## dubbo.properties

  dubbo.application.name=annotation-provider

  dubbo.registry.address=zookeeper://127.0.0.1:2181

  dubbo.protocol.name=dubbo

  dubbo.protocol.port=20880

3,Spring Boot配置 

例:

## application.properties

  # Spring boot application
  spring.application.name=dubbo-externalized-configuration-provider-sample
  # Base packages to scan Dubbo Component: @com.alibaba.dubbo.config.annotation.Service
  dubbo.scan.base-packages=com.alibaba.boot.dubbo.demo.provider.service

  # Dubbo Application
  ## The default value of dubbo.application.name is ${spring.application.name}
  ## dubbo.application.name=${spring.application.name}
  # Dubbo Protocol

  dubbo.protocol.name=dubbo
  dubbo.protocol.port=12345

  ## Dubbo Registry
  dubbo.registry.address=N/A

  ## DemoService version
  demo.service.version=1.0.0

4,Dubbo API配置

例:

public static void main(String[] args) throws IOException {
    ServiceConfig<GreetingsService> service = new ServiceConfig<>();
    service.setApplication(new ApplicationConfig("first-dubbo-provider"));
    service.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234"));
    service.setInterface(GreetingsService.class);
    service.setRef(new GreetingsServiceImpl());
    service.export();
    System.out.println("first-dubbo-provider is running.");
    System.in.read();}

二,dubbo的高可用配置

高可用是分布式CAP理论中的一环,一个稳定的分布式或者微服务架构的软件系统,高可用是必不可少的
 
dubbo实现高可以服务的体现(这也是dubbo高可用需要解决的问题):
  1. 监控中心宕机不影响使用,只是丢失部分采样数据
  2. 数据库宕机后,注册中心仍然可以提供缓存提供服务查询,但不能注册新服务
  3. 注册中心集群部署后,任意一台宕机后,将自动切换到另一台
  4. 注册中心全部宕机后,服务提供者和服务消费者仍然可以通过本地缓存通信
  5. 服务提供者无状态,任意一台宕掉后,不影响使用
  6. 服务提供者全部宕机,服务消费者应用将无法使用,并无线重连等待服务提供者恢复正常状态
通过高可用的,可以减少系统的不能提供服务的时间,也能提供突发异常时的使用策略

一,zookeeper宕机与dubbo直连

zookeeper的两个主要用途:
 
1,分布式开发中:zookeeper在java分布式应用开发中做为一个注册中心使用,每个节点的服务注册到zookeeper中(服务的类信息,服务的url地址等),消费者获取调用服务,向注册中心zookeeper获取,zookeeper注册中心返回服务的url地址,消费者通过url地址找到服务并调用
 
2,大数据集群中:zookeeper在hadoop分布式集群中,做为一个节点的监控和动态上下线,防止namenode的脑裂,datenode的突然宕机,实现大数据集群的高可用
有无注册中心的情况下服务端和消费端的连接获取方式:
1,有注册中心
注册中心充当了一个中间角色,负责所有服务调度和发现(本质上就是解耦)

2,无注册中心(直连的方式)
没有注册中心的中间发现和调度,dubbo可以通过直连的方式实现消费端和服务端的中间的通信
 
直连:直接通过url地址请求

配置直连:
1,配置文件配置:在消费端配置服务端的url
<dubbo:reference id="xxxService" interface="com.alibaba.xxx.XxxService" url="dubbo://localhost:20890" />
2,注解配置
@DubboReference(url = "")
注册中心宕机后的策略:
1,在注册中心集群化部署中
① 一个注册中心宕机,会进行切换到其他可用的注册中心
② 注册中心全部宕机后,会进行无线重连注册中心,但服务提供者和服务消费者仍然可以通过本地缓存通信
2,在单个注册中心
服务提供者和消费者会进行无线重连,服务提供者和服务消费者也可以通过本地缓存通信

二,集群模式下dubbo的负载均衡策略

在集群负载均衡时,Dubbo提供了多种均衡策略,默认为随机调用
 
四种负载均衡策略:
1,Random LoadBalance:随机按照权重的负载均衡
  • 随机,按权重设置随机概率。
  • 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。

2,RoundRobin LoadBalance:轮询按照公约权重的负载均衡
  • 轮询,按公约后的权重设置轮询比率。
  • 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

3,LeastActive LoadBalance:按照最小活跃数的负载均衡
  • 最少活跃调用数,相同活跃数的随机,活跃数指调用前后时间。
  • 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数时间差越大。

4,ConsistentHash LoadBalance:一致性hash的负载均衡
  • 一致性 Hash,相同参数的请求总是发到同一提供者。
  • 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
  • 缺省只对第一个参数 Hash,如果要修改,请配置 <dubbo:parameter key="hash.arguments" value="0,1" />
  • 缺省用 160 份虚拟节点,如果要修改,请配置 <dubbo:parameter key="hash.nodes" value="320" />

负载均衡的配置:
服务端服务级别:
<dubbo:service interface="..." loadbalance="roundrobin" />
客户端服务级别:
<dubbo:reference interface="..." loadbalance="roundrobin" />
服务端方法级别:
<dubbo:service interface="...">

<dubbo:method name="..." loadbalance="roundrobin"/>

</dubbo:service>
客户端方法级别:
<dubbo:reference interface="...">

<dubbo:method name="..." loadbalance="roundrobin"/>

</dubbo:reference>

三,服务的熔断和服务的降级

说到服务熔断和服务降级就需要说分布式架构中高并发情况下容易出现的一种系统性的风险服务雪崩

一,服务雪崩

概念:服务雪崩就好比是蝴蝶效应,一个局部服务出现问题,却产生了无比严重的后果,以至于最后整体结构都发生改变,服务整体瘫痪
例:有三个服务分别是userA,userB,userC。它们相互调用,其中userA调用userB,userB调用userC,它们形成一个调用链

产生服务雪崩:
当提供userC的机器出现宕机,网络故障,并发高导致CPU瘫痪等情况,导致userC服务不可用,然而userB服务又调用userC导致userB超时调用失败,userA又调用userB,userB不可用导致userA也调用失败,最终导致整个服务调用链路都不可用,整体瘫痪,整个系统不可用就跟雪崩一样

服务雪崩产生的常见原因:
  1. 突增的并发访问:比如爬虫或者黑客攻击
  2. 程序BUG:比如出现死锁,死循环,资源未释放
  3. 硬件问题:机器宕机,光纤断掉,断电等
访问雪崩的解决方案:服务熔断

二,服务熔断

服务熔断:当下游服务因为某种原因得不可用或者响应慢,上游服务为了保证整体服务的可用性将不再调用此服务,直接返回或者调用容错方法,释放资源,如果目标服务情况好转则恢复调用
例:通俗点来说的话熔断机制就好比以前大学的时候宿舍是不是不允许使用大功率电器,一旦使用大功率电器,电流过大,保险丝就会融化,宿舍立马就会跳闸断电,当电压稳定的时候又会继续通电,熔断器就好比是那保险丝
服务熔断机制很好的避免了服务雪崩情况的发生,本质上它是一种特定的容错机制,避免出现系统性的错误
 
注:熔断其实是框架级别的处理,这套熔断机制的设计,基本用的是断路器模式
目前流行的熔断器很多,例如阿里出的Sentinel,以及最多人使用的Hystrix
在dubbo中并没有明确的提到服务熔断处理机制,但dubbo提供了服务容错处理,也可以整合Hystrix进行服务熔断处理

三,服务降级

服务降级:服务降级主要用于当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,将一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用 
 
例:当服务器压力剧增的情况下,根据实际情况,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心服务正常运行高效运作
注:服务降级本质上是业务层面上的,临时屏蔽某个出错的非关键业务,保证核心业务的稳定
服务降级的方式:
  1. 延迟服务:定时任务处理,或者使用MQ延时处理,例:大量用户服务B服务,B服务可以通过MQ消息队列,进行缓冲
  2. 页面降级:页面点击按钮全部置成无效,或者页面显示维护状态
  3. 关闭非核心服务:比如电商可以关闭推荐服务,运费险,广告等,保证主线程的核心服务下单付款
  4. 写降级:就是不保证强一致性,比如秒杀抢购,可以只进行Cache的更新返回,然后通过MQ异步扣除库存DB,保证最终的一致性,将DB降为Cache
  5. 读降级:多级缓存模式,如果后端服务有问题,可以降级为只读缓存,这种方式适用于对读一致性要求不高的场景
Dubbo服务降级的配置:
  • mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响(在消费者端降级)
  • 还可以改为 mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

四,服务容错

一,Dubbo集群模式的配置
1,服务端配置
<dubbo:service cluster="failsafe" />
2,消费端配置
<dubbo:reference cluster="failsafe" />
二,Dubbo集群的容错模式:
① Failove Cluster
失败自动切换,当出现失败,重试其他服务器,通常用于读操作,但重试会带来更长的延迟,可以提供retries=""来设置重试次数(不含第一次)
自动切换的配置:
1,服务提供端配置
<dubbo:service retries="2" />
2,服务消费端配置
<dubbo:reference retries="2" />

② Failfast Cluster

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

③ Failsafe Cluster

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

④ Failback Cluster

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

⑤ Forking Cluster

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。

⑥ Broadcast Cluster

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

三,整合Hystrix

hystrix旨在通过控制那些访问远程系统,服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力,hystrix具备拥有回退机制和断路器功能的线程隔离,请求缓存和请求打包,以及监控和配置等功能
1,配置spring-cloud-starter-netfix-hystrix
spring boot官方提供了对hytrrix的集成,直接在pom中加入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
2,在Application类上增加@EnableHystrix来启用hystrix starter
 
3,通过@HystrixCommand代理方法,并回调方法
 
例:
1,启动类
@EnableDubbo
@EnableHystrix//开启服务容错
@SpringBootApplication
public class BootServerProviderApplication {

public static void main(String[] args) {
SpringApplication.run(BootServerProviderApplication.class, args);
}
}
2,服务提供端
@Service//暴露服务
@DubboService
public class UserServiceimpl implements UserService {
@HystrixCommand//使用Hystrix来带来这个方法的异常
public List<UserAdress> getbean() {

if(Math.random()>0.5){

throw new RuntimeException();

}

UserAdress wql1 = new UserAdress("WQL", "湖南衡阳!");

UserAdress wql2 = new UserAdress("FQ","深圳");

List<UserAdress> list = new ArrayList<UserAdress>();

list.add(wql1);
list.add(wql2);
return list;
}}
3,服务消费者
@Controller
public class OrderAddress {

@DubboReferenc
UserService userService;

@HystrixCommand(fallbackMethod ="err" )//fallbackMethod回调方法,一旦调用远程服务出错,调用会调方法
public List<UserAdress> getwql(){

return userService.getbean();

}

@GetMapping(value = "/")
@ResponseBody
public List<UserAdress> err(){//定义回调方法

return Arrays.asList(new UserAdress("回调方法","测试回调"));
}}

三,启动时检查

Dubbo默认启动时会检测服务是否可用,不可用时会抛出异常,Spring的初始化会失败,以便在项目上线前发现问题,默认 check="true"

也可以通过chack = "true"关闭检查,比如:测试时,有些服务不关心,或者出现服务循环依赖必须一方先启动

如果Spring容器懒加载,或者通过API编程延迟引用服务,要关闭check,否则服务临时不可用时,会抛出异常

Spring配置check:

1,关闭某个服务的启动时检测(在reference引用服务中关闭):

<dubbo:reference interface="com.foo.BarService" check="false" />

2,关闭所以服务的启动时检测(在cunsumer消费者中关闭):

<dubbo:consumer check="false" />

3,关闭注册中心的启动时检查

<dubbo:registry check="false" />

配置说明:

dubbo.reference.check=false,强制改变所有 reference 的 check 值,就算配置中有声明,也会被覆盖。
dubbo.consumer.check=false,是设置 check 的缺省值,如果配置中有显式的声明,如:<dubbo:reference check="true"/>,不会受影响。
dubbo.registry.check=false,前面两个都是指订阅成功,但提供者列表是否为空是否报错,如果注册订阅失败时,也允许启动,需使用此选项,将在后台定时重试。

例:关闭服务提供者provider,测试服务消费者的情况

1,默认check=true时:关闭provider,启动consumer报错

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'orderAddress': Injection of @DubboReference dependencies is failed; nested exception is java.lang.IllegalStateException: Failed to check the status of the service com.example.bootserverprovider.service.UserService. No provider available for the service com.example.bootserverprovider.service.UserService from the url zookeeper://192.168.68.152:2181/org.apache.dubbo.registry.RegistryService?anyhost=true&application=boot-server-consumer&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&init=false&interface=com.example.bootserverprovider.service.UserService&metadata-type=remote&methods=getbean&pid=15588&qos.enable=false®ister.ip=192.168.68.1&release=2.7.8&remote.application=boot-server-provider&side=consumer&sticky=false×tamp=1625072365565 to the consumer 192.168.68.1 use dubbo version 2.7.8
    at com.alibaba.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor.postProcessPropertyValues(AbstractAnnotationBeanPostProcessor.java:146) ~[spring-context-support-1.0.8.jar:na]

2,check=false时,启动consumer:正常启动

四,多版本

在 Dubbo 中为同一个服务配置多个版本
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。

可以按照以下的步骤进行版本迁移:
1,在低压力时间段,先升级一半提供者为新版本
2,再将所有消费者升级为新版本
3,然后将剩下的一半提供者升级为新版本

老版本服务提供者配置: 
<dubbo:service interface="com.foo.BarService" version="1.0.0" /> 

新版本服务提供者配置:
<dubbo:service interface="com.foo.BarService" version="2.0.0" />

老版本服务消费者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />


新版本服务消费者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />

 

详细情况请去dubbo官网


路漫漫其修远兮,吾将上下而求索