赞
踩
首先,从Dubbo支持的配置来源说起,默认有四种配置来源:
JVM System Properties,-D 参数
Externalized Configuration,外部化配置(如application.yml)
ServiceConfig、ReferenceConfig 等编程接口采集的配置(通过编码形式,如写个配置类标注为@Component)
本地配置文件 dubbo.properties
覆盖关系
优先级顺序:
retries 属性表示远程服务调用重试次数,不包括第一次调用,不需要重试请设为0。默认为2.
如果该服务名下有多台服务器,当出现失败时,会轮询自动切换尝试其他服务器。
@DubboService 和@DubboReference都有重试次数属性。@DubboService标注在对应接口的实现类上,@DubboReference标注在要注入的远程调用对象上。
@Service // 放进springboot容器中 //服务提供者接口实现类需要被@DubboService 驱动 @DubboService(retries = 3) //默认重试次数是2次 public class UserServiceImpl implements UserService { public List<UserAddress> getUserAddressList(String userId) { System.out.println("UserServiceImpl..1....."); UserAddress address1 = new UserAddress(1, "北京市朝阳区麦肯锡", "1", "李老师", "010-56253825", "Y"); UserAddress address2 = new UserAddress(2, "深圳市宝安区珠江工厂)", "1", "王老师", "010-56253825", "N"); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return Arrays.asList(address1,address2); } } }
控制请求超时,打印结果:
UserServiceImpl..1.....
UserServiceImpl..1.....
UserServiceImpl..1.....
UserServiceImpl..1.....
使用注解形式无法实现方法级别的属性设置
<dubbo:service retries="2" />
或
<dubbo:reference retries="2" />
或
<dubbo:reference>
<dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
由于网络或服务端不可靠,会导致出现一种不确定的中间状态(超时)。为了避免超时导致客户端资源挂起耗尽,必须设置超时时间。timeout该属性远程服务调用超时时间(毫秒),默认时间为1000ms。
配置的覆盖规则:
配置的覆盖规则:
1、 方法级别的优于接口级别,接口级别的优于全局配置。
2、 Consumer端配置优于Provider
consumer.xml
服务提供者
项目结构
主启动类
由于是使用xml暴露服务的,所以不用使用@EnableDubbo
DubboProviderMain20881.java
//@EnableDubbo //使用xml暴露服务时候不用@EnableDubbo注解
@SpringBootApplication
public class DubboProviderMain20881 {
public static void main(String[] args) {
SpringApplication.run(DubboProviderMain20881.class,args);
}
}
服务接口实现类之一UserServiceImpl
package com.johnny.dubbo.service.impl; import com.johnny.dubbo.entity.UserAddress; import com.johnny.dubbo.service.UserService; import org.apache.dubbo.config.annotation.DubboService; import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; /** * @author Johnny Lin * @date 2021/7/8 17:42 */ @Service // 放进springboot容器中 //服务提供者接口实现类需要被@DubboService 驱动 @DubboService // 一定一定要加上@DubboService注解暴露远程服务给消费者 一开始就是就没有加上 public class UserServiceImpl implements UserService { public List<UserAddress> getUserAddressList(String userId) { System.out.println("UserServiceImpl..v1....."); UserAddress address1 = new UserAddress(1, "北京市朝阳区麦肯锡", "1", "李老师", "010-56253825", "Y"); UserAddress address2 = new UserAddress(2, "深圳市宝安区珠江工厂)", "1", "王老师", "010-56253825", "N"); // try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(address1.getId()+"\t"+address1.getUserAddress()); System.out.println(address2.getId()+"\t"+address2.getUserAddress()); return Arrays.asList(address1,address2); } }
服务接口实现类之一UserServiceImpl2.java
package com.johnny.dubbo.service.impl; import com.johnny.dubbo.entity.UserAddress; import com.johnny.dubbo.service.UserService; import org.apache.dubbo.config.annotation.DubboService; import org.springframework.stereotype.Service; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; /** * @author Johnny Lin * @date 2021/7/8 17:42 */ @Service // 放进springboot容器中 //服务提供者接口实现类需要被@DubboService 驱动 @DubboService // 一定一定要加上@DubboService注解暴露远程服务给消费者 一开始就是就没有加上 public class UserServiceImpl2 implements UserService { public List<UserAddress> getUserAddressList(String userId) { System.out.println("UserServiceImpl..v2....."); UserAddress address1 = new UserAddress(3, "北京市朝阳区麦肯锡", "1", "李老师", "010-56253825", "Y"); UserAddress address2 = new UserAddress(4, "深圳市宝安区珠江工厂)", "1", "王老师", "010-56253825", "N"); // try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(address1.getId()+"\t"+address1.getUserAddress()); System.out.println(address2.getId()+"\t"+address2.getUserAddress()); return Arrays.asList(address1,address2); } }
服务提供者配置文件provider.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://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"> <!-- 1、指定当前服务/应用的名字(同样的服务名字相同,不要和别的服务同名) --> <dubbo:application name="user-service-dubbo-provider"></dubbo:application> <!-- 2、指定注册中心的位置 --> <!-- <dubbo:registry address="zookeeper://192.168.59.123:2181"></dubbo:registry> --> <dubbo:registry protocol="zookeeper" address="192.168.59.123:2181"></dubbo:registry> <!-- 3、指定通信规则(通信协议?通信端口) --> <dubbo:protocol name="dubbo" port="20882"></dubbo:protocol> <!-- 4、暴露服务 interface:面向的接口 ref:指向服务的真正的实现对象 version: 版本,通过指定版本可以实现灰度发布 --> <dubbo:service interface="com.johnny.dubbo.service.UserService" ref="userServiceImpl" timeout="1000" version="1.0.0"> <dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method> </dubbo:service> <!--统一设置服务提供方的规则 --> <dubbo:provider timeout="1000"></dubbo:provider> <!-- 服务的实现 --> <bean id="userServiceImpl" class="com.johnny.dubbo.service.impl.UserServiceImpl"></bean> <dubbo:service interface="com.johnny.dubbo.service.UserService" ref="userServiceImpl2" timeout="1000" version="2.0.0"> <dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method> </dubbo:service> <bean id="userServiceImpl2" class="com.johnny.dubbo.service.impl.UserServiceImpl2"></bean> <!-- 连接监控中心 --> <dubbo:monitor protocol="registry"></dubbo:monitor> </beans>
消费者
项目结构
注意application
yaml 和 consumer0.xml 都没有用到
**主启动类 ConsumerMain8081 **
@SpringBootApplication
//@EnableDubbo开启Dubbo注解 该注解中有@DubboComponentScan 作用是扫描dubbo注解所在包
//由于使用xml文件暴露服务 所以不需要该注解
//@EnableDubbo
public class ConsumerMain8081 {
public static void main(String[] args) {
SpringApplication.run(ConsumerMain8081.class,args);
}
}
服务实现类 OrderServiceImpl
package com.johnny.dubbo.service.impl; import com.johnny.dubbo.entity.UserAddress; import com.johnny.dubbo.service.OrderService; import com.johnny.dubbo.service.UserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; /** * @author Johnny Lin * @date 2021/7/8 0:18 */ @Service public class OrderServiceImpl implements OrderService { //Reference注解引用服务远程调用 // @DubboReference // UserService userService; //通过xml配置文件暴露接口时,接口的调用使用@Autowired注解,不用 @DubboReference // 相当于通过spring将这个接口对象注入了 @Resource private UserService userService; public List<UserAddress> initOrder(String userId) { System.out.println("OrderService 1……"); return userService.getUserAddressList(userId); } }
**服务控制类 OrderController **
package com.johnny.dubbo.controller; import com.johnny.dubbo.entity.UserAddress; import com.johnny.dubbo.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * @author Johnny Lin * @date 2021/7/8 23:50 */ @RestController public class OrderController { @Autowired private OrderService orderService; @GetMapping("/initOrder/{id}") public List<UserAddress> initOrder(@PathVariable("id")String userId) { return orderService.initOrder(userId); } }
配置文件consumer.xml
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" 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"> <dubbo:application name="order-service-dubbo-consumer"></dubbo:application> <dubbo:registry id="register" protocol="zookeeper" address="192.168.59.123:2181" timeout="25000"></dubbo:registry> <!-- retries 重试次数: 不包含第一次调用 0代表不重试 幂等操作(如查询、删除、修改)需要设置重试次数 非幂等操作(如新增) 不能设置重试次数 --> <!-- timeout 超时等待时间: 为0 表示默认是1000ms--> <!-- 配置当前消费者的统一规则 设置全局超时时间 check=false表示所有服务启动时都不检查是否有提供者--> <dubbo:consumer timeout="5000" check="false" ></dubbo:consumer> <!-- 指定接口以及特定方法超时配置 --> <!-- 通过dubbo:reference 的timeout属性设置接口级的超时时间--> <!-- 通过dubbo:reference 标签生成一个id为userService的远程代理对象 该对象的timeout属性 --> <!-- register 属性从指定注册中心注册获取服务列表,在多个注册中心时使用,值为<dubbo:registry>的id属性,多个注册中心ID用逗号分隔 缺省向所有registry注册 --> <!-- 通过dubbo:reference的version属性指定使用消费端的版本实现灰度发布,* 表示所有版本,也可以指定版本 --> <dubbo:reference interface="com.johnny.dubbo.service.UserService" id="userService" registry="register" timeout="6000" version = "*"> <!-- 通过dubbo:method 的timeout属性设置方法级的超时时间 方法级别的起作用--> <dubbo:method name="getUserAddressList" timeout="1000" ></dubbo:method> </dubbo:reference> <!-- 指定监控中心协议 会在注册中心寻找监控中心地址 否则直连监控中心 因此无需再填写详细地址--> <dubbo:monitor protocol="registry" ></dubbo:monitor> <!-- <dubbo:monitor address="127.0.0.1:7001"></dubbo:monitor> --> </beans> 非幂等操作(如新增) 不能设置重试次数 --> <!-- timeout 超时等待时间: 为0 表示默认是1000ms--> <!-- 配置当前消费者的统一规则 设置全局超时时间 所有服务都不检查--> <dubbo:consumer timeout="5000" check="false" ></dubbo:consumer> <!-- 指定接口以及特定方法超时配置 --> <!-- 设置接口级的超时时间--> <!-- 通过dubbo:reference 标签生成一个id为userService的远程代理对象 该对象的timeout属性 --> <dubbo:reference interface="com.johnny.dubbo.service.UserService" id="userService" timeout="6000"> <!-- 设置方法级的超时时间 --> <dubbo:method name="getUserAddressList" timeout="1000" ></dubbo:method> </dubbo:reference> <!-- 指定监控中心协议 会在注册中心寻找监控中心地址 否则直连监控中心 因此无需再填写详细地址--> <dubbo:monitor protocol="registry"></dubbo:monitor> <!-- <dubbo:monitor address="127.0.0.1:7001"></dubbo:monitor> --> </beans>
No provider available from registry 192.168.59.123:2181 for service com.johnny.dubbo.service.UserService on consumer 192.168.255.1 use dubbo version 2.7.8, please check status of providers(disabled, not registered or in blacklist)
困扰了老子一天 是在想不明白为什么 监控中心也显示该消费服务没有提供者
原来服务提供者对应的接口实现类上也需要加上@DubboService 注解才能暴露服务给消费者
当一个接口实现,出现不兼容升级时,可以使用版本号过渡。版本号不同的服务相互不引用。可以按照以下步骤进行版本迁移:
老版本服务提供者配置:
<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:reference id="barService" interface="com.foo.BarService" version="*" />
注意当provider只有一个版本时 如果消费者version写的是*,那么消费者会找不到对应服务。
1、 精确优先(即官网所说的 方法级优先、接口级次之,全局配置再次之)
2、 消费者设置优先(同等级别下,消费则优先,提供者次之)。
Spring配置
consumer.xml
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" 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"> <!-- retries 重试次数: 不包含第一次调用 0代表不重试 幂等操作(如查询、删除、修改)需要设置重试次数 非幂等操作(如新增) 不能设置重试次数 --> <!-- timeout 超时等待时间: 为0 表示默认是1000ms--> <!-- 设置全局超时时间--> <dubbo:consumer timeout="5000" ></dubbo:consumer> <!-- 指定接口以及特定方法超时配置 --> <!-- 设置接口级的超时时间--> <!-- 通过dubbo:reference 标签生成一个id为userService的远程代理对象 该对象的timeout属性 --> <dubbo:reference interface="com.johnny.dubbo.service.UserService" id="userService" timeout="6000"> <!-- 设置方法级的超时时间 --> <dubbo:method name="getUserAddressList" timeout="5000" ></dubbo:method> </dubbo:reference> </beans>
SSM 方式直接调用时直接读取配置文件从容器中获取该bean
@SpringBootApplication
@EnableDubbo //开启Dubbo注解 该注解中有@DubboComponentScan 作用是扫描dubbo注解所在包
public class ConsumerMain8081 {
public static void main(String[] args) {
SpringApplication.run(ConsumerMain8081.class,args);
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
UserService userService = applicationContext.getBean(UserService.class);
System.out.println(111);
System.out.println(userService.getUserAddressList("36"));
}
}
在 Dubbo 中利用本地存根在客户端执行部分逻辑
消费端:
UserServiceStub
package com.johnny.dubbo.service.impl; import com.johnny.dubbo.entity.UserAddress; import com.johnny.dubbo.service.UserService; import org.apache.dubbo.common.utils.StringUtils; import java.util.List; /** * @author Johnny Lin * @date 2021/7/11 23:44 */ public class UserServiceStub implements UserService { private final UserService userService; /** * 传入的是userService远程的代理对象 * @param userService */ public UserServiceStub(UserService userService) { super(); this.userService = userService; } @Override public List<UserAddress> getUserAddressList(String userId) { // TODO Auto-generated method stub System.out.println("UserServiceStub stub....."); if(!StringUtils.isEmpty(userId)) { return userService.getUserAddressList(userId); } return null; } }
consumer.xml
<dubbo:reference interface="com.johnny.dubbo.service.UserService" id="userService"
registry="register" timeout="6000"
version = "1.0.0" stub="com.johnny.dubbo.service.impl.UserServiceStub">
参考文档:
Dubbo 中的端口使用情况
高可用,通过设计,减少系统不能提供服务的时间
绕过注册中心,直连本地服务提供者:
在consumer的服务实现类OrderServiceImpl上
@DubboReference(url = "dubbo://localhost:20885")
private UserService userService;
现象: zookeeper注册中心宕机,还可以消费dubbo暴露的服务
原因:
dubbo的健壮性
其他情况:
使用@Reference(url="")
Dubbo提供了多种负载均衡策略,缺省为random随机调用
随机,按权重设置随机概率
轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
一致性 Hash,相同参数的请求总是发到同一提供者。
当服务器压力剧增时,根据业务情况及流量,为保证服务端的核心业务的正常运作和避免客户端的过长等待,对于一些服务和页面有策略的不处理或换种简单的方式处理(如提示用户系统繁忙)。
在集群调用失败时,Dubbo提供了多种容错方案,缺省为failover重试
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries=“2” 来设置重试次数(不含第一次)。
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知等操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。
集群模式配置
按照以下示例在服务提供方和消费方配置集群模式
<dubbo:service cluster="failsafe" />
或
<dubbo:reference cluster="failsafe" />
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。