Dubbo(二)

一.Dubbo的常用属性配置

1. check -启动时检查

Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"。

可以通过 check="false" 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。
开启配置:
	消费者:
		1.	<dubbo:reference check="false"/> 默认是true
		2.	<dubbo:consumer check="false"/>	//全局配置,配置所有的consumer关闭启动时检查
	生产者:
		1.	<dubbo:service check="false"/>
		2.	<dubbo:provider check="false"/>	//配置所有的provider关闭启动时检查

配置的查找顺序:

  • 方法级优先,接口级次之,全局配置再次之
  • 如果级别一样,则消费方优先,提供方次之
    在这里插入图片描述

2. version -多版本

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

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

老版本服务提供者配置:

<dubbo:service interface="com.qf.service.DemoService" version="1.0.0" />

新版本服务提供者配置:

<dubbo:service interface="com.qf.service.DemoService" version="2.0.0" />

老版本服务消费者配置:

<dubbo:reference id="demoService" interface="com.qf.service.DemoService" version="1.0.0" />

新版本服务消费者配置:

<dubbo:reference id="demoService" interface="com.qf.service.DemoService" version="2.0.0" />

如果不需要区分版本,可以按照以下的方式配置(随机匹配):

<dubbo:reference id="demoService" interface="com.qf.service.DemoService" version="*" />

测试:

生产者:

提供两个实现类模拟两个版本的服务

public class DemoServiceImpl implements DemoService {
    public String sayHello(String name) {
        return "hello1"+name;
    }
}

public class DemoServiceImpl2 implements DemoService {
    public String sayHello(String name) {
        return "hello2"+name;
    }
}

修改配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--    1.给服务起个名-->
    <dubbo:application name="dubbo-provider"/>
<!--    2.将zookeeper路径指定-->
    <dubbo:registry address="zookeeper://114.55.219.117:2181"/>
<!--    3.指定建立socket链接的端口号-->
    <dubbo:protocol name="dubbo" port="20880"/>
<!--    4.服务提供-->
    <dubbo:service interface="com.qf.service.DemoService" ref="demoService" version="1.0.0"/>
    <dubbo:service interface="com.qf.service.DemoService" ref="demoService2" version="2.0.0"/>
    <!--    5.将DemoServiceImpl配置到spring容器中去-->
    <!--旧版本-->
    <bean id="demoService" class="com.qf.service.impl.DemoServiceImpl"></bean>
    <!--新版本-->
    <bean id="demoService2" class="com.qf.service.impl.DemoServiceImpl2"></bean>
</beans>

消费者:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!--取名-->
    <dubbo:application name="dubbo-consumer"/>
    <!--zookeeper地址-->
    <dubbo:registry address="zookeeper://114.55.219.117:2181"/>
    <!--生成远程服务代理,和生产者的service包名一致-->
    <!--随机使用哪个版本-->
    <dubbo:reference interface="com.qf.service.DemoService" id="demoService" version="*"/>
    <!--将controller交给spring去管理-->
    <bean class="com.qf.controller.DemoController" id="demoController">
        <property name="demoService" ref="demoService"/>
    </bean>
</beans>

3. timeout超时时间

指定服务被调用的超时时间
在method,reference,service,consumer,provider中添加timeout属性,并指定超时时间的毫秒值

测试:
生产者:
分别在两个实现类方法中让线程睡眠3秒

public class DemoServiceImpl implements DemoService {
    public String sayHello(String name) {
        try {
            Thread.sleep(3000);
        } catch (Exception e){

        }
        return "hello1"+name;
    }
}

public class DemoServiceImpl2 implements DemoService {
    public String sayHello(String name) {
        try {
            Thread.sleep(3000);
        } catch (Exception e){

        }
        return "hello2"+name;
    }
}

消费者:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!--取名-->
    <dubbo:application name="dubbo-consumer"/>
    <!--zookeeper地址-->
    <dubbo:registry address="zookeeper://114.55.219.117:2181"/>

    <!--生成远程服务代理,和生产者的service包名一致-->
    <!--随机使用哪个版本-->
    <!--
        分别在reference,method和consumer里设置了timeout,method优先级最高,所有执行method中的timeout
    -->
    <dubbo:reference interface="com.qf.service.DemoService" id="demoService" version="*" timeout="4000">
        <dubbo:method name="sayHello" timeout="2000"/>
    </dubbo:reference>

    <dubbo:consumer timeout="5000"/>
    <!--将controller交给spring去管理-->
    <bean class="com.qf.controller.DemoController" id="demoController">
        <property name="demoService" ref="demoService"/>
    </bean>
</beans>

4. retries重试次数

retries指定重试次数,当调用服务失败时,指定重试的次数,不包括第一次,默认值为2

幂等: 多次重复操作和一次操作产生的影响是一样的。
非幂等:多次重复操作和一次操作产生的影响是不一样的。

在开发中要根据服务具有以上哪个特性决定重试次数

<dubbo:method retries="2"/>
<dubbo:reference retries="2"/>
<dubbo:service retries="2"/>
<dubbo:consumer retries="2"/>
<dubb:provider retries="2"/>

5.本地存根

在controller调用远程服务的代理对象之前,先调用本地的stub方法,在方法中可以做参数的校验,异常的捕获,容错性,可以在调用远程服务前,就规避一些问题,避免远程调用后才发生
相当于,controller先调用了stub方法然后在stub中调用远程服务

创建一个服务接口的实现类

public class DemoServiceStup implements DemoService{

    private DemoService demoService;

    //dubbo会将真正的远程服务代理对象传递过来
    public DemoServiceStup(DemoService demoService){
        this.demoService = demoService;
    }

    public String sayHello(String name) {
        if(name.contains("黄")){
            return "不合法";
        }
        String result = demoService.sayHello(name);
        return result;
    }
}

开启配置:

 <dubbo:reference interface="com.qf.service.DemoService" stub="com.qf.service.DemoServiceStup"  id="demoService" version="*" >
        <dubbo:method name="sayHello" timeout="4000"/>
    </dubbo:reference>

在这里插入图片描述

二. SpringBoot配置Dubbo的属性

1. yml文件 + 注解

在启动类上添加注解
	@EnableDubbo
	
全局级别,直接在yml文件中配置
服务级别,直接配置在注解中
使用yml文件 + 注解,无法细粒度到方法级别,只能配置到引用服务的级别
1.check
	可以在yml中指定	dubbo.consumer.check=false
	也可以在注解上指定	@Reference(check=false)
2.version
					dubbo.consumer.version=1.0.0
					@Reference(version="1.0.0")	
3.timeout
		 			dubbo.consumer.timeout=0
					@Reference(timeout=xxx)	
4.retries
					dubbo.consumer.retries=xx
					@Reference(retries=xxx)
5.stub	
					dubbo.consumer.stub=xxx
					@Reference(stub="xxx")

2. xml文件方式

在启动类上添加注解,引入指定的xml配置文件
	@ImportResource(locations={"xxx"})

当使用xml文件配置后,要采用spring的注解,从spring容器中获取代理对象的实例

采用这种方式spring boot可以细粒度化控制配置信息

测试:

@SpringBootApplication
//@EnableDubbo
@ImportResource(locations = {"classpath:application-dubbo.xml"})
public class DubboApplication {

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

}

controller

@RestController
@RequestMapping("/demo")
public class DemoController {

//    @Reference
//    @Resource
    @Autowired
    private DemoService demoService;

    @GetMapping(value = "/hhh",produces = "text/html;charset-utf-8")
    public String hhh(){
        String str = demoService.sayHaHaHa();
        return str;
    }
}

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <dubbo:application name="dubbo-springboot-consumer"/>

    <dubbo:registry address="zookeeper://114.55.219.117:2181"/>

    <dubbo:reference interface="com.qf.service.DemoService" id="demoService"/>

</beans>

测试成功:
在这里插入图片描述

3.采用Dubbo的API方式

基于最原生的方式,直接创建config类
查看Dubbo的DubboNameSpaceHandler类,查看需要使用到的config类

需要在启动类上,添加dubbo的注解扫描
	@DubboComponentScan
在引用服务时,使用
	(dubbo的注解)
	@Reference -> 订阅服务
	@Service -> 暴露服务

生产者:

@SpringBootApplication
//@EnableDubbo
@DubboComponentScan
public class DubboApplication {

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

}

config配置文件

@SpringBootConfiguration
public class DemoServiceImplConfig {

    //application.name
    @Bean
    public ApplicationConfig applicationConfig(){
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("dubbo-springboot-provider");
        return applicationConfig;
    }

    //zookeeper的地址
    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://114.55.219.117:2181");
        return registryConfig;
    }

    //socket的协议和端口
    @Bean
    public ProtocolConfig protocolConfig(){
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setPort(20880);
        protocolConfig.setName("dubbo");
        return protocolConfig;
    }

    /*@Bean
    public ServiceBean<DemoService> demoServiceBean(){
        ServiceBean<DemoService> demoServiceBean = new ServiceBean<>();
        demoServiceBean.setInterface("com.qf.service.DemoService");
        demoServiceBean.setId("demoService");
        return demoServiceBean;
    }*/
}

对外暴露的服务:

@Service    //dubbo中的注解
public class DemoServiceImpl implements DemoService {

    @Override
    public String sayHaHaHa() {
        return "哈哈哈哈哈哈哈哈哈额";
    }
}

消费者:

@SpringBootApplication
//@EnableDubbo
//@ImportResource(locations = {"classpath:application-dubbo.xml"})
@DubboComponentScan
public class DubboApplication {
    public static void main(String[] args) {
        SpringApplication.run(DubboApplication.class, args);
    }

}

config配置:

@SpringBootConfiguration
public class DemoServiceConfig {

    //1.dubbo.application.name=xxx
    @Bean
    public ApplicationConfig applicationConfig(){
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("dubbo-springboot-consumer");
        return applicationConfig;
    }

    //2.dubbo.registry.address=xxx
    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://114.55.219.117:2181");
        return registryConfig;
    }

    //3.dubbo.reference interface=xxx
    //ReferenceBean继承了ReferenceConfig了,所以这里两者都行
    /*@Bean
    public ReferenceConfig<DemoService> referenceConfig(){
        ReferenceConfig<DemoService> demoServiceReferenceConfig = new ReferenceConfig<>();
        demoServiceReferenceConfig.setInterface("com.qf.service.DemoService");
        demoServiceReferenceConfig.setId("demoService");
        return demoServiceReferenceConfig;
    }*/
    @Bean
    public ReferenceBean<DemoService> referenceBean(){
        ReferenceBean<DemoService> demoServiceReferenceBean = new ReferenceBean<>();
        demoServiceReferenceBean.setInterface("com.qf.service.DemoService");
        demoServiceReferenceBean.setId("demoService");
        //方法级别的设置
        List<MethodConfig> methodConfigs = new ArrayList<>();
        MethodConfig methodConfig = new MethodConfig();
        methodConfig.setName("sayHello");
        //超时timeout
        methodConfig.setTimeout(1000);
        //重试次数retries
        methodConfig.setRetries(0);
        //设置到list
        methodConfigs.add(methodConfig);
        //设置到referenceBean
        demoServiceReferenceBean.setMethods(methodConfigs);

        return demoServiceReferenceBean;
    }

    //4.dubbo.consumer..

}

controller

@RestController
@RequestMapping("/demo")
public class DemoController {

    @Reference	//订阅服务,这里必须使用@Reference
    private DemoService demoService;

    @GetMapping(value = "/hhh",produces = "text/html;charset-utf-8")
    public String hhh(){
        String str = demoService.sayHaHaHa();
        return str;
    }
}

三.高可用

1.zookeeper宕机-dubbo直连

1.服务之间可以正常通讯,突然zookeeper宕机
	->服务之间的调用还可以正常执行
	->如果有服务之前从未调用过,由于本地没有缓存,无法调用
	->即便服务之间可以正常调用,还是会丢失信息
	->搭建zookeeper集群,避免zookeeper宕机引起的各种问题
2.如果舍弃zookeeper或者其他各种注册中心,dubbo提供了直连方式
	->提供者将注册中心地址设置为N/A
		如:dubbo.registry.address=N/A
	->消费者在服务的订阅上直接指定提供者的协议IP和端口		protocol://host:post
		如:@Reference(url = "dubbo://127.0.0.1:20880")
	好处:
		配置简单
		可以舍弃zookeeper注册中心
	缺点
		1.没有一个集中的管理工具,去治理整个dubbo
		2.没有基于zookeeper的注册中心,导致缺少负载均衡,等待一系列的功能
		3.需要记住很多很多服务的ip和port,维护麻烦

2.dubbo的负载均衡

1.负载均衡的策略

Random LoadBalance
	随机,按权重设置随机概率。
	在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance
	轮询,按公约后的权重设置轮询比率。
	存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActive LoadBalance
	最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
	使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHash LoadBalance
	一致性 Hash,相同参数的请求总是发到同一提供者。
	当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。

2.配置方式

1.@Reference | @Service 中配置loadBalance属性,指定四种负载均衡机制中的一种
	random | roundrobin | leastactive | consistenthash
2.关于随机和轮询的权重,推荐在监控中心动态的修改

测试:

准备一台和生产者端口不一致的服务器如下:
在生产者的条件下复制一个tomcat端口8081和dubbo端口20881
在这里插入图片描述
在消费者@Reference中加上负载均衡的属性策略

  @Reference(loadbalance = "consistenthash")

3.服务容错策略

1.默认的容错
	failover,失败重试,指定retries重试次数
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

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

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

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

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

配置方式:

<dubbo:service cluster="failsafe" />
<dubbo:reference cluster="failsafe" />

4.服务的降级

1.dubbo的降级方式

可以通过服务降级功能 [1] 临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。
向注册中心写入动态配置覆盖规则:

RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));

其中:

  • mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
  • 还可以改为 mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

2.Hystrix
1.导入依赖

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.0.4.RELEASE</version>
        </dependency>

2.在启动类上添加注解

@EnableHystrix

@SpringBootApplication
//@EnableDubbo
@DubboComponentScan
@EnableHystrix
public class DubboApplication {

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

3.在提供者的服务类的方法上添加注解

	@Override
    @HystrixCommand
    public String sayHaHaHa(String name) {
        if(Math.random()>0.5){
            throw new RuntimeException();
        }
        return "哈哈哈哈哈哈哈哈哈额"+port;
    }

4.在消费者调用远程服务的方法上,添加注解

//@HystrixCommand(fallBackMethod="xxx")
//出现问题访问xxx方法

	@HystrixCommand(fallbackMethod = "xxx")
    @GetMapping(value = "/hhh",produces = "text/html;charset-utf-8")
    public String hhh(String name){
        String str = demoService.sayHaHaHa(name);
        return str;
    }

    public String xxx(String name){
        return "网络开小差了";
    }
发布了19 篇原创文章 · 获赞 7 · 访问量 1868

猜你喜欢

转载自blog.csdn.net/X_Q_B_J/article/details/104884399
今日推荐