dubbo:基于注解的常用配置

之前记录了基于springboot的dubbo入门案例,今天在此基础上记录dubbo官网介绍的常用属性配置(基于注解),dubbo读取我们配置的属性时是有优先级的,优先级如下图:  

                  

  如图所示,优先级的属性依次为:虚拟机参数>xml配置>dubbo.properties,虚拟机参数即程序启动之前我们通过-D配置的dubbo属性,xml配置即我们项目中自己写的xml文件或者是springboot中的application.properties,当公共配置很简单,没有多注册中心,多协议等情况,或者想多个 Spring 容器想共享配置的情况下可以用dubbo.properties作为缺省配置;需要注意的是我这里的测试用例都是写在application.properties中,当然如果感觉不习惯,也可以跟普通maven项目一样新建xml文件,在xml中进行配置,只是不要忘了在springboot的启动类中添加@ImportResource(locations="xml路径")注解来引入就行,下面开始记录dubbo的常用配置:

  一、启动时检查(check)

  默认情况下dubbo是开启自动检查的,即当项目启动时会自动检查其依赖的服务是否开启,如果没开是会阻止spring的初始化的,即check=true;我们可以将check置为false来关闭启动时检查,如我们在测试或者对其他服务没有依赖的时候可以关闭检查,在springboot中我们可以进行如下配置来关闭启动时检查:

  1、关闭某个服务的启动检查

  在引用该服务的@Reference注解上添加check=false,即@Reference(check = false)

  2、关闭所有服务的启动时检查

  在application.properties中添加dubbo.consumer.check=false

  二、超时(timeout,默认为1000),重试次数(retries)

  超时:当消费者调用提供者时由于网络等原因有可能会造成长时间拿不到响应,而请求还在不断的发过来这就有可能造成线程阻塞,使用timeout设置超时时间当超过该时间就会抛出异常。设置如下:

        当只针对某个服务时:@Reference(timeout=XXX)  

        当针对所有服务时:dubbo.consumer.timeout=XXX   

  重试次数:当调用失败或超时后重新尝试调用的次数,其值不包含第一次

     当只针对某个服务时:@Reference(retries=XXX)

        当针对所有服务时:dubbo.consumer.retries=XXX

  三、多版本(灰色发布)

  当出现系统版本升级时,新版本有可能不够稳定,这时候可以通过设置version来进行平滑的过渡,下面是dubbo官网的版本迁移步骤:

    在低压力时间段,先升级一半提供者为新版本,再将所有消费者升级为新版本,然后将剩下的一半提供者升级为新版本

    而新旧版本我们可以通过version来定义,假设老版本的version=1.0.0新版本的version=2.0.0;

    老版本服务提供者:@Service(version="1.0.0")

    新版本服务提供者:@Service(version="2.0.0")

    老版本服务消费者:@Reference(version="1.0.0")

    新版本服务消费者:@Reference(version="2.0.0")

    这样新旧版本就完美错开,只会调用version对应的服务,如果调用的时候不需要区分版本号,则进行如下配置:@Reference(version=“*”),这样dubbo会默认在新老版本中随机调用。

注:若服务提供者设置了版本号,也即加了@Service(version="1.0.0")注解,那么服务消费者也必须加上版本号,即@Reference(version="1.0.0")或者@Reference(version="*"),否则消费端会因找不到对应服务而报错。

  四、本地存根(stub)

    正常情况下,服务搭建成功后服务的实现一般都在服务端,但有时候我们可能需要在客户端做些逻辑操作,比如参数验证,缓存处理以及调用失败后伪造容错数据的处理等等,这时候我们就需要用到dubbo的本地存根机制,它能在远程服务调用前在客户端进行相关的逻辑操作,具体步骤如下:

    1、在客户端写一个远程调用服务的实现,并生成有参构造参数为远程服务,代码如下:

 

package com.gmall.service.stub;

import java.util.List;

import com.gmall.api.OrderService;
import com.gmall.bean.OrderInfo;

/**
 * OrderService的本地存根实现
 * @Author Jun
 * @date 2019年12月2日 下午5:43:23
 */
public class OrderServiceStub implements OrderService {

	private OrderService orderService;

	/**
	 * 有参构造 dubbo会自动将远程OrderService注入进来
	 * @param orderService
	 */
	public OrderServiceStub(OrderService orderService) {
		super();
		this.orderService = orderService;
	}

	/**
	 * 在远程调用前可以进行判断
	 */
	@Override
	public List<OrderInfo> findList() {
		//参数校验、缓存处理等等
		double i = Math.random();
		if(i > 0.5) {
			//do some thing
		}
		//校验通过后调用远程服务
		return orderService.findList();
	}

}

   2、进行存根配置

    在客户端调用远程服务的注解上添加stub,值为我们客户端实现的远程服务类的全路径名,如@Reference(stub = "com.gmall.service.stub.OrderServiceStub)

代码如下:

@Reference(stub="com.gmall.service.stub.OrderServiceStub")
private OrderService orderService;

   五、负载均衡

    dubbo提供了四种负载均衡策略,分别是:

    1、Random LoadBalance 按权重的随机负载均衡,也是dubbo默认的负载均衡策略;

    2、RoundRobin LoadBalance 按权重的轮询负载均衡,即在轮询的基础上添加了权重的策略;

    3、LeastActive LoadBalance 最少活跃调用数,相同活跃数的随机访问,活跃数指调用前后的计数差即响应时间的长短,这种策略可以使响应慢的提供者收到的请求较少,大大提供系统性能;

    4、ConsistentHash LoadBalance 一致性哈希,相同参数的请求总是发到同一提供者;

    负载均衡的配置:@Reference(loadbalance = "roundrobin"),loadbalance 的值即为四种负载均衡的名称,全部小写。

  六、服务降级

    当服务器压力过大时,我们可以通过服务降级来使某些非关键服务的调用变得简单,可以对其直接进行降权,即客户端优先发送请求到权重大的服务,若将服务权重设置为0,则服务请求将不再分配到这个服务,从而降低这部分的服务器资源消耗。服务降级的相关配置可以直接在dubbo-admin的监控页面进行配置,在dubbo-admin管理页面下的服务治理-权重调整,可以自定义想要降级服务的权重(默认权重都是100),点击“创建”,在弹出的窗口中输入想要降权的服务id、应用名,设置队=对应的权重,然后保存即可生效。

  七、集群容错

    在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。下面列举dubbo支持的容错策略:

    Failover Cluster:失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="XXX" 来设置重试次数(不含第一次)。

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

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

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

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

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

注:在实际项目中,生产环境中,我们用failover模式时可以这样设计服务接口,遵循接口隔离原则 ,查询服务与写操作服务隔离,查询接口我们可以配置 retries="2" ;在写操作接口我们配置 retries="0" ,如果不设置为0, 超时,会重新连接,会出现重复写的情况,所以使用failover模式时,我们要进行读写操作接口隔离,且写操作接口retries=0。

       配置如下:@Reference(cluster = "failsafe"),这里表示使用失败安全的容错策略。

    还有一种springcloud默认的容错策略Hystrix,Hystrix旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能,下面介绍如何整合Hystrix:

    1、分别在提供者和消费者添加Hystrix依赖,或者直接在公共接口层添加,代码如下:

<!-- hystrix依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
	<version>1.4.5.RELEASE</version>
</dependency>

加入此依赖后,启动springboot可能会出现如下错误:

java.lang.NoSuchMethodError: org.springframework.boot.builder.SpringApplicationBuilder.<init>([Ljava/lang/Object;)

此错误是由于springboot与Hystrix版本不兼容导致的,我使用的springboot版本是2.0.3,2.x版本可能都会出现这种情况,解决方法如下:

① 将刚才添加的Hystrix Maven依赖修改为下面的依赖(即去掉版本号):

<!-- hystrix依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

② 在pom.xml文件的 </dependencies> 节点下面添加如下内容:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

③ 若pom.xml文件报错:Multiple annotations found at this line,可以在当前项目工程上 右键 -> run as -> Maven clean -> Maven install,构建完成后(若出现报错,直接忽略),再 右键 -> Maven -> Update Project,此时pom.xml文件错误已经消失了,可以正常启动项目。

    2、在提供者和消费者的启动类上添加@EnableHystrix来启用hystrix;

package com.gmall;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;

@SpringBootApplication
@EnableDubbo
@EnableHystrix
public class BootStart {

	public static void main(String[] args) throws Exception {
		SpringApplication.run(BootStart.class, args);
	}

}

    3、在提供者需要容错的方法上添加@HystrixCommand表示使用hystrix代理:

package com.gmall.service.impl;

import java.util.List;

import org.assertj.core.util.Lists;

import com.alibaba.dubbo.config.annotation.Service;
import com.gmall.api.OrderService;
import com.gmall.bean.OrderInfo;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

//此注解是 com.alibaba.dubbo.config.annotation.Service 下的注解,并非springboot下的@Service注解,若当前实现类需要交由springboot管理,建议使用@Component注解
@Service(version = "1.0.0")
public class OrderServiceImplV1 implements OrderService {

	@HystrixCommand
	@Override
	public List<OrderInfo> findList() {

		System.err.println("I'M 1.0.0 ==============");

		OrderInfo o1 = new OrderInfo(1L, "Tom", "笔记本", 12.5D, "1.0.0");
		OrderInfo o2 = new OrderInfo(2L, "Jack", "铅笔", 3.5D, "1.0.0");
		OrderInfo o3 = new OrderInfo(3L, "Lily", "橡皮", 5.0D, "1.0.0");

		return Lists.newArrayList(o1, o2, o3);
	}

}

    4、在消费者需要容错的方法上添加@HystrixCommand,还可以给其添加属性,表示调用出错后处理错误的方法:

package com.gmall.service.impl;

import java.util.List;

import org.apache.curator.shaded.com.google.common.collect.Lists;
import org.springframework.stereotype.Component;

import com.alibaba.dubbo.config.annotation.Reference;
import com.gmall.api.OrderService;
import com.gmall.bean.OrderInfo;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@Component
public class OrderServiceImpl implements OrderService {

	//@Reference dubbo注解
	@Reference(stub="com.gmall.service.stub.OrderServiceStub", version="*", check=false)
	private OrderService orderService;

	@HystrixCommand(fallbackMethod="doError")
	@Override
	public List<OrderInfo> findList() {
		return orderService.findList();
	}

	/**
	 * 调用远程方法报错后的回调方法
	 * @return
	 */
	public List<OrderInfo> doError() {
		return Lists.newArrayList(new OrderInfo().setId(1L).setShopName("error"));
	}

}

 

   至此已经完成对Hystrix的整合,当远程调用失败(报错、超时等)后,就会进入到我们自定义的fallbackMethod方法中,返回我们预先设定好的值,从而达到服务容错的要求。

八、推荐用法

  根据官网介绍,整理了部分dubbo的配置规则:

1、在Provider端尽量多配置Consumer端属性,原因如下:

  • 作服务的提供方,比服务消费方更清楚服务的性能参数,如调用的超时时间、合理的重试次数等
  • 在 Provider 端配置后,Consumer 端不配置则会使用 Provider 端的配置,即 Provider 端的配置可以作为 Consumer 的缺省值 。否则,Consumer 会使用 Consumer 端的全局设置,这对于 Provider 是不可控的,并且往往是不合理的

    Provider 端尽量多配置 Consumer 端的属性,让 Provider 的实现者一开始就思考 Provider 端的服务特点和服务质量等问题。

    建议在 Provider 端配置的 Consumer 端属性有:

  1. timeout:方法调用的超时时间;
  2. retries:失败重试次数,缺省是 2;
  3. loadbalance:负载均衡算法 ,缺省是随机 random。还可以配置轮询 roundrobin、最不活跃优先 leastactive 和一致性哈希 consistenthash 等;
  4. actives:消费者端的最大并发调用限制,即当 Consumer 对一个服务的并发调用到上限后,新调用会阻塞直到超时,在方法上配置 dubbo:method 则针对该方法进行并发限制,在接口上配置 dubbo:service,则针对该服务进行并发限制。

2、在Provider端配置合理的Provider属性

     建议在 Provider 端配置的 Provider 端属性有:

  1. threads:服务线程池大小;
  2. executes:一个服务提供者并行执行请求上限,即当 Provider 对一个服务的并发调用达到上限后,新调用会阻塞,此时 Consumer 可能会超时。在方法上配置 dubbo:method 则针对该方法进行并发限制,在接口上配置 dubbo:service,则针对该服务进行并发限制。

3、配置优先级:方法级优先,接口级次之,全局配置再次之;如果级别一样,则消费方优先,提供方次之。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值