Dubbo配置_2

本文详细介绍了Dubbo的配置原则,包括加载顺序、启动时检查、超时时间、重试次数、版本号管理和本地存根。此外,还讨论了集群容错配置,并提供了与SpringBoot整合的多种方式。通过案例展示了如何配置超时、重试和版本控制,强调了幂等操作和非幂等操作的重试策略差异。

配置的官方网址http://dubbo.apache.org/zh-cn/docs/user/configuration/xml.html

1、配置原则

1 .properties加载顺序

1-1dubbo.properties 加载顺序 优先1,其次2 ,最后3 

上面图中的顺序对应下面的3中情况

1.JVM 启动 -D 参数优先,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。

2.XML 次之,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。相当于和spring整合项目里的provider.xml,与springboot整合的application.properties文件

3.Properties 最后,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置,比如应用名

为了便于测试效果,我们在boot-user-service-provider项目中创建一个dubbo.properties文件

我们只修改对应的端口号,便于区分

1.虚拟机参数 -Ddubbo.protocol.port=20880

2.application.properties文件中的修改 

3.dubbo.properties文件中的配置 只需配置一行端口号

dubbo.protocol.port=20882

运行启动程序 开后台日志信息

1.设计虚拟机参数 ,对应的两个配置文件也配置好了,优先加载的20880 虚拟机参数是优先

2. 删除虚拟机参数,看另外两个的顺序,先加载application.properties 文件

3.注释掉application.properties文件中的配置 ,最后加载的是dubbo.properties文件

2、启动时检查

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

可以通过 check="false" 关闭检查,调用的时候才回去检查调用的服务是否启动,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。

另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到 null 引用,如果 check="false",总是会返回引用,当服务恢复时,能自动连上。

如图即使我们注释掉了user-service-consumer 项目中的条用的代码,依然是报错的

当我们修改配置comsumer.xml文件中 增加check="false" 这个配置再看控制台的消息

    <!-- 调用的服务 -->
    <dubbo:reference id="userService" interface="com.atguigu.gmail.service.UserService"
    check="false"/>

可以看到增加一段配置后控制台没有报错了

这个只是一个消费服务这的服务不检查,如果实际的项目的服务消费者比较多,我们一一的配置比较麻烦,还有一个中同一配置消费服务不检查的配置还是在consumer.xml文件中 增加,效果和上面的是一样

<!-- 配置当前消费者同一规则:所有的服务都不检查 -->
    <dubbo:consumer check="false"></dubbo:consumer>

3、超时时间

由于网络或服务端不可靠,会导致调用出现一种不确定的中间状态(超时)。为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间。timeout 设置超时时间,一般配置在服务端,具体情况也可以配置在客户端

我们以user-serivce-provider 和user-service-consumer项目为测试时案例

consumer.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://dubbo.apache.org/schema/dubbo"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
   
    <context:component-scan base-package="com.atguigu.gmail.service.impl"></context:component-scan>
	<!-- 服务名称 -->
    <dubbo:application name="order-service-consumer"/>
    
    <!--  注册中心地址 -->
    <dubbo:registry address="zookeeper://10.5.96.48:2181"/>
    
    <!-- 调用的服务 -->
    <!-- timeout="0" 超时  默认是1000豪秒-->
    <dubbo:reference  interface="com.atguigu.gmail.service.UserService"
    id="userService"/>
    
    <!-- 配置当前消费者同一规则:所有的服务都不检查 -->
    <dubbo:consumer check="false"></dubbo:consumer>

   <!-- 配置监控中心 -->
	<!--  下面的两种都可以 -->
	<!--  ① 是默认配置自动发现 -->
	<!--  ② 直连监控中心-->
	<!--  <dubbo:monitor protocol="registry"></dubbo:monitor> -->
	<dubbo:monitor address="127.0.0.1:7070"></dubbo:monitor>
</beans>

我们让服务提供者睡4秒

package com.atguigu.gmail.service.impl;

import java.util.Arrays;

import java.util.List;

import com.atguigu.gmail.bean.UserAddress;
import com.atguigu.gmail.service.UserService;

public class UserServiceImpl implements UserService {

	public List<UserAddress> getUserAddressList(String userId) {
		UserAddress address1 = new UserAddress(1,"东长安街89号","1","李老师","13278977","1");
		UserAddress address2 = new UserAddress(2,"西长安街89号","1","李老师","13278977","1");
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return Arrays.asList(address1,address2);
	}

}

运运行服务的提供者,先注册到注册中心,在运行服务的消费者,代码前面都写过就不贴了,

报错,我们并没有设置超时时间,可是依然报超时1000ms ,这是因为timeout的超时时间默认是1000豪秒

第二次我们设置超时时间是5000ms

 <!-- 调用的服务 -->
    <!-- timeout="0" 超时 -->
    <dubbo:reference  interface="com.atguigu.gmail.service.UserService"
    id="userService" timeout="5000"/>

看运行结果,这次就补贴图了,可以自己验证,可以调用成功

超时的优先级别图,有上到下优先级别,先方法①,后接口②,全局最后③  ,每个级别都是对应的消费方优先

服务消费者还可以这样配置超时时间,指定方法名,和方法的超时时间 ,和全局的配置

 <!-- 调用的服务 -->
    <!-- timeout="0" 超时 -->
    <dubbo:reference  interface="com.atguigu.gmail.service.UserService"
    id="userService" timeout="5000">
        <!-- 可以指定方法名,也可以指定超时时间 -->
    	<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
    </dubbo:reference>
    
    <!-- 配置当前消费者同一规则:所有的服务都不检查 -->
    <dubbo:consumer check="false" timeout="5000"></dubbo:consumer>

服务提供者也可以设置超时时间

<!-- 4 暴露服务 ref 指向服务的真正实现对象  -->
	<dubbo:service interface="com.atguigu.gmail.service.UserService"
	 ref="userServiceImpl" timeout="1000"></dubbo:service>

超时规则

1.精确优先(方法级优先,接口次之,全局配置再次之)

2.消费者设置优先(如果级别一样,则消费方优先,提供方次之)

案例 :如果我们在提供方配置设置方法级别的超时时间2000ms,服务消费方接口设置超时时间4000ms ,这样的配置依然会报超时错误,因为优先的级别是按照上面的图,先方法级别,接口级别的生效方式

4、重试次数

失败自动切换,当出现失败,重试其它服务器,但重试会带来更长延迟。可通过 retries="3" 来设置重试次数(不含第一次)一共就是4次。一般配合的是timeout使用,一般配置在客户端

 <!-- 调用的服务 -->
    <!-- timeout="0" 超时 -->
    <!-- retires=“” 重试次数,不包含第一次 -->
    <dubbo:reference  interface="com.atguigu.gmail.service.UserService"
    id="userService" timeout="5000" retries="3">
    </dubbo:reference>

这里有一个说明 就是幂等操作和非幂等操作

1.幂等操作(设置重置次数)【查询、修改、删除】 这些操作的结果是相同的

2.非幂等操作(不能设置重置次数)【新增】因为有可能在超时时间内,这一次操作已经发送给数据库,只不过还没有执行完成,重试后可能插入相同的数据很多次

 5、版本号

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

可以按照以下的步骤进行版本迁移:

0.在低压力时间段,先升级一半提供者为新版本

1.再将所有消费者升级为新版本

2.然后将剩下的一半提供者升级为新版本

代码实现

我们创建两个版本的UserServiceImple 一个是如图

UserServiceImpl.java代码  这个是旧版本代码


public class UserServiceImpl implements UserService {
	public List<UserAddress> getUserAddressList(String userId) {
		System.out.println("UserServiceImpl...old");
		UserAddress address1 = new UserAddress(1,"东长安街89号","1","李老师","13278977","1");
		UserAddress address2 = new UserAddress(2,"西长安街89号","1","李老师","13278977","1");
		
		return Arrays.asList(address1,address2);
	}
}

UserServiceImpl2.java代码 这个是新版本代码

public class UserServiceImpl2 implements UserService {

	public List<UserAddress> getUserAddressList(String userId) {
		System.out.println("UserServiceImpl...new");
		UserAddress address1 = new UserAddress(1,"东长安街89号","1","李老师","13278977","1");
		UserAddress address2 = new UserAddress(2,"西长安街89号","1","李老师","13278977","1");
		
		return Arrays.asList(address1,address2);
	}
}

我们在provider.xml文件中进行配置版本  其他的代码不动,只增加了dubbo对外暴露的服务和实例bean

<!-- 4 暴露服务 ref 指向服务的真正实现对象  -->
	<dubbo:service interface="com.atguigu.gmail.service.UserService" 
	ref="userServiceImpl01" version="1.0.0"></dubbo:service>
	
	<bean class="com.atguigu.gmail.service.impl.UserServiceImpl" 
	id="userServiceImpl01" ></bean>
	
	<dubbo:service interface="com.atguigu.gmail.service.UserService" 
	ref="userServiceImpl02" version="2.0.0"></dubbo:service>
	
	<bean class="com.atguigu.gmail.service.impl.UserServiceImpl2"
	id="userServiceImpl02"></bean>

我们在消费者服务的配置之中增加对应的调用的服务consumer.xml 在<dubbo:reference > 标签中增加了version="1.0.0" 

①启动服务提供者主启动类ProviderMainApplication,然后在启动消费者主启动类ConsumerMainApplication

②修改consumer.xml 在<dubbo:reference > 标签中增加了version="2.0.0",然后在启动消费者主启动类ConsumerMainApplication

  <!-- 调用的服务 -->
    <!-- timeout="0" 超时 -->
    <dubbo:reference  interface="com.atguigu.gmail.service.UserService"
    id="userService" timeout="5000" retries="3" version="1.0.0">
        <!-- 可以指定方法名,也可以指定超时时间 -->
    	<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
    </dubbo:reference>

两次操作截图

我们可以看到ProviderMainApplication控制台的两次调用的日志,第一次对应的是旧版本的服务,第二次是新版本的服务,这样就可以控制我们调用服务对于版本的控制了。如果我们在consumer.xml 中配置version="*"调用的版本就是随机的

6、本地存根

远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub [1],然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。

consumer.xml代码 增加一个本地存个属性

 <!-- 调用的服务 -->
    <!-- timeout="0" 超时 -->
    <dubbo:reference  interface="com.atguigu.gmail.service.UserService"
    id="userService" timeout="5000" retries="3" version="1.0.0"
    stub="com.atguigu.gmail.service.impl.UserServiceStub">

创建一个本地存根的实现类UserServiceIStub.java

构造方法传入的远程服务的代理对象,实现接口的方法中可以增加一些验证,缓存或是其他的代码,通过就可以通过代理对象调用远程的服务,否则不调用了。 

public class UserServiceStub implements UserService {
	
	private final UserService userService;
    /**
     * 传入的是userService 远程代理对象
     * @param userService
     */
	public UserServiceStub(UserService userService) {
		super();
		this.userService = userService;
	}

	public List<UserAddress> getUserAddressList(String userId) {
		System.out.println("UserServiceStub...");
		//在这个验证之前我们可以实现一些需要的业务验证
		if(StringUtils.isEmpty(userId)){
			//此时代理对象调用远程服务的
			return userService.getUserAddressList(userId);
		}
		return null;
	}
}

 7Dubbo集群容错配置

        <dubbo:consumer cluster="failover" retries="2" forks="2"/>

       1、Failover  当出现失败,重试其他服务。retires="2",来设置重试次数(不包含第一次)幂等 行操作使用,如读操作

       2、Failfast  快速失败,只发起一次调用,失败立即报错  非幂等操作,如写操作

       3、Failsafe 出现异常时,直接忽略 无关紧要的旁支操作,如打日志

       4、Failback 后台记录失败请求,定时重发后续专业处理

       5、Forking 并行调用多个服务器,只要一个成功即返回 fork="2"来设置最并行数。

8 Dubbo与SpringBoot 整合的三种方法

      1)导入dubbo-starter,在application.properties配置属性,使用@Service【暴露服务】使用@Reference【应用服务】这种方式一定要在SpringBootApplication 上增加@EnableDubbo 开启基于注解的配置

      2)导入dubbo-starter,保留dubbo.xml配置文件

             将application.properties文件中的配置都注释掉,也就是相当于provider.xml文件放入到resource资源目录下,暴露服务上面@Service注解也可以去掉了

3)使用注解API的方式

            将每一个组件创建到容器中 项目结构如图

 

写一个配置类MyDubboConfig.java 对应的Bean 也就是provider.xml 的配置

@Configuration
public class MyDubboConfig {
	
	/**
	 * <dubbo:application name="boot-user-service-provider">
	 * </dubbo:application>	
	 * 对应下面的代码
	 * @return
	 */
	@Bean
	public ApplicationConfig applicationConfig(){
		ApplicationConfig applicationConfig = new ApplicationConfig();
		applicationConfig.setName("boot-user-service-provider");
		return applicationConfig;	
	}
	
	/**
	 * <dubbo:registry protocol="zookeeper" address="10.5.96.48:2181">
	 * </dubbo:registry>
	 * @return
	 */
	@Bean
	public RegistryConfig registryConfig(){
		RegistryConfig registryConfig = new RegistryConfig();
		registryConfig.setProtocol("zookeeper");
		registryConfig.setAddress("10.5.96.48:2181");
		return registryConfig;
	}
	
	/**
	 * <!-- 3 指定通信规则  通信协议,通信端口-->
	<dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
	 * @return
	 */
	@Bean
	public ProtocolConfig protocolConfig(){
		ProtocolConfig protocolConfig = new ProtocolConfig();
		protocolConfig.setName("dubbo");
		protocolConfig.setPort(20882);
		return protocolConfig;
	}
	
	/**
	 * <dubbo:service interface="com.atguigu.gmail.service.UserService" 
	ref="userServiceImpl01" version="1.0.0">
	<dubbo:method name="getUserAddressList" timeout="3000"></dubbo:method>
	</dubbo:service>
	 */
	public ServiceConfig<UserService> userServiceConfig(UserService userService){
		ServiceConfig<UserService> serviceConfig = new ServiceConfig();
		serviceConfig.setInterface(UserService.class);
		serviceConfig.setRef(userService);
		serviceConfig.setVersion("1.0.0");
		
		//配置每一个method的信息
		MethodConfig methodConfig = new MethodConfig();
		methodConfig.setName("getUserAddressList");
		methodConfig.setTimeout(1000);
		
		//将method 的设置关联到service 配置中
		List<MethodConfig> methods = new ArrayList<>();
		methods.add(methodConfig);
		serviceConfig.setMethods(methods);
		return serviceConfig;
		
	}

}

 

总结

        1.dubbo的service注解有两功能,第一注册服务spring容器,第二能暴露服务--容器有连个实例

        2.zk的集群还是单节点,对应服务来说,没有区别,集群抗灾

        3.dubbo的消费/服务信息,都存储zk节点上,后台admin是读取这个值

        4.把serviceimpl配置进入spring容器,管理服务,(dubbo只能支持spring管理的服务)

        5.消费方继承服务属性

                   只有服务提供方,知道service参数怎么配置最合适

案例 :UserService指定了协议,发布对应的服务,而VipUserService 没有指定协议,则会发布两个对应协议的实例,也就是房补两个实例

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

<dubbo:service interface="com.xxx.service.UserService" ref="userService" protocol="rmi"/>
<dubbo:service interface="com.xxx.service.VipUserService" ref="vipUserService"/>

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值