Dubbo
一、dubbo配置
1、配置覆盖策略
JVM 启动 -D 参数优先
,这样可以使用户在部署和启动时进行参数重写,比如在启动时需改变协议的端口。
XML 次之
,如果在 XML 中有配置,则 dubbo.properties 中的相应配置项无效。
Properties 最后
,相当于缺省值,只有 XML 没有配置时,dubbo.properties 的相应配置项才会生效,通常用于共享公共配置
,比如应用名。
2、启动检查
消费者每次启动都会自动检查注册中心中他订阅的方法
spring 配置文件:
关闭某个服务的启动时检查 (没有提供者时报错):
<dubbo:reference interface="com.foo.BarService" check="false" />
关闭所有服务的启动时检查 (没有提供者时报错):
<!--配置当前消费者的统一规则,所有的服务都不检查,-->
<dubbo:consumer check="false" />
关闭注册中心启动时检查 (注册订阅失败时报错):
<dubbo:registry check="false" />
dubbo.properties:
dubbo.reference.com.foo.BarService.check=false
dubbo.reference.check=false
dubbo.consumer.check=false
dubbo.registry.check=false
配置的含义:

dubbo.reference.check=false
,强制改变所有 reference 的 check 值,就算配置中有声明,也会被覆盖。
dubbo.consumer.check=false
,是设置 check 的缺省值,如果配置中有显式的声明,如:<dubbo:reference check="true"/>
,不会受影响。
dubbo.registry.check=false
,前面两个都是指订阅成功,但提供者列表是否为空是否报错,如果注册订阅失败时,也允许启动,需使用此选项,将在后台定时重试。
3、超时时间
由于网络或服务端不可靠,会导致调用出现一种不确定的中间状态(超时)。为了避免超时导致客户端资源(线程)挂起耗尽,必须设置超时时间。
1)、Dubbo消费端
全局超时配置
<dubbo:consumer timeout="5000" />
指定接口以及特定方法超时配置
<dubbo:reference interface="com.foo.BarService" timeout="2000">
<dubbo:method name="sayHello" timeout="3000" />
</dubbo:reference>
2)、Dubbo服务端
全局超时配置
<dubbo:provider timeout="5000" />
指定接口以及特定方法超时配置
<dubbo:provider interface="com.foo.BarService" timeout="2000">
<dubbo:method name="sayHello" timeout="3000" />
</dubbo:provider>
4、配置原则
配置的覆盖规则:
1、精确优先(方法级优先,接口级次之,全局配置再次之)
2、消费者设置优先(如果
级别一样
,则消费方优先,提供方次之)
5、重试次数
失败自动切换,当出现失败,重试其它服务器,但重试会带来更长延迟。可通过 retries=“2” 来设置重试次数(不含第一次,也就是说设置为3,则会有4次)。
操作类型:
-
幂等操作:设置重试次数【查询、更新、删除】
-
非幂等操作:不能设置重试次数【新增】
重试次数配置如下:
<dubbo:service retries="2" />
或
<dubbo:reference retries="2" />
或
<dubbo:reference>
<dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
6、版本号
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
在低压力时间段,先升级一半提供者为新版本
再将所有消费者升级为新版本
然后将剩下的一半提供者升级为新版本
【老】版本服务 【提供者】 配置:
<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="*" />
7、本地存根
远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub 1,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。
在 interface 旁边放一个 Stub 实现,它实现 UserService 接口,并有一个传入远程 UserService 实例的构造函数
<dubbo:service interface="com.achang.gmall.service.UserService" stub="com.achang.gmall.service.UserServiceStub" />
提供 Stub 的实现:【有点过滤器拦截器的味道,先判断是否合法,再去调用】
Stub实例里 必须有可传入 Proxy 的构造函数。【oo】
public class UserServiceStub implements UserService{
private final UserService userService;
//传入的是userService的远程代理对象
// 构造函数传入真正的远程代理对象【oo】
public UserServiceStub(UserService userService) {
this.userService = userService;
}
public List<UserAddress> getUserAddressList(String userId) {
System.out.println("UserServiceStub...............");
// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存,或预先验证参数是否合法,等等
if (StringUtils.isEmpty(userId)){
return userService.getUserAddressList(userId);
}
return null;
}
}
8、SpringBoot整合
上面在<dubbo:service
中配置的属性,都可以如下在@Service注解()配置
<dubbo:service interface="com.foo.BarService" version="1.0.0" />
配置timeout
属性
@Service(timeout = ) //暴露服务
public class UserServiceImpl implements UserService {
}
SpringBoot与dubbo整合的三种方式:
1)、导入dubbo-starter,在application.proterties配置文件中配置,
—使用
@Service
注解【暴露服务】、使用@Reference
注解【引用服务】—要在application.proterties中配置
dubbo.scan.base-packages=
告诉其上面注解的位置
2)、保留dubbo,xml配置文件的方式:
—导入dubbo-starter
—通过使用@ImportResource(locations=“classpath:XXXX.xml”),来导入之前原始的xml配置文件
3)、使用注解API方式:
—将每一个组件手动创建到容器中,让dubbo来扫描其他的自己
写一个配置类,来手动创建到容器中,对比上面和下面的写法
@Configuration
public class MyDubboConfig {
@Bean
public ApplicationConfig applicationConfig(){
ApplicationConfig config = new ApplicationConfig();
config.setName("boot-user-service-provider");
return config;
}
@Bean
public RegistryConfig registryConfig(){
RegistryConfig config = new RegistryConfig();
config.setAddress("localhost:2181");
config.setProtocol("zookeeper");
return config;
}
@Bean
public ProtocolConfig protocolConfig(){
ProtocolConfig config = new ProtocolConfig();
config.setName("dubbo");
config.setPort(20880);
return config;
}
@Bean
public MonitorConfig monitorConfig(){
MonitorConfig config = new MonitorConfig();
config.setProtocol("registry");
return config;
}
}
并在主启动类上标注@EnableDubbo(scanBasePackages=com.achang.gamll)
指定dubbo接口的扫描路径中的@Service
暴露的服务位置
二、高可用
1、zookeeper宕机与dubbo直连
现象:zookeeper注册中心宕机,还可以消费dubbo暴露的服务。
原因:
健壮性:
1 监控中心宕掉不影响使用,只是丢失部分采样数据
2 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
3 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
4 注册中心【全部宕掉】后,服务提供者和服务消费者仍能通过【本地缓存通讯】
5 服务提供者无状态,任意一台宕掉后,不影响使用
6 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
高可用:通过设计,减少系统不能提供服务的时间;
也可以通过dubbo直连的方式:
通过@Reference(url =)
来指定提供者的ip地址:端口
@Reference(url = "localhost:20882")
UserService userService;
2、集群下dubbo负载均衡配置
在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random 随机调用
。
负载均衡策略:
- Random LoadBalance
—>基于权重的随机
负载均衡机制【默认】
随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
- RoundRobin LoadBalance
—>基于权重的轮询
负载均衡机制
轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
- LeastActive LoadBalance
—>最少活跃数
-负载均衡机制
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
- ConsistentHash LoadBalance
—> 一致性hash
-负载均衡机制
一致性 Hash,
相同参数的请求总是发到同一提供者
。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。算法参见:http://en.wikipedia.org/wiki/Consistent_hashing
缺省只对第一个参数 Hash,如果要修改,请配置
<dubbo:parameter key="hash.arguments" value="0,1" />
缺省用 160 份虚拟节点,如果要修改,请配置
<dubbo:parameter key="hash.nodes" value="320" />
- 设定引用注册中心时,使用什么负载机制
- 通过dubbo页面来快速设置 提供者 权重
3、整合hystrix,服务熔断与降级处理
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)、集群容错
在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。
集群容错模式
Failover Cluster
失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。
重试次数配置如下:
<dubbo:service retries="2" />
或
<dubbo:reference retries="2" />
或
<dubbo:reference>
<dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。
集群模式配置
按照以下示例在服务提供方和消费方配置集群模式
<dubbo:service cluster="failsafe" />
或
<dubbo:reference cluster="failsafe" />
3)、整合hystrix
Hystrix 旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能
1、配置spring-cloud-starter-netflix-hystrix
spring boot官方提供了对hystrix的集成,直接在pom.xml里加入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
然后在主Application配置启动类上增加@EnableHystrix
来启用hystrix starter:
@SpringBootApplication
@EnableHystrix //启用hystrix starter
public class ProviderApplication {
}
2、配置Provider端
在Dubbo的Provider上增加@HystrixCommand配置,fallbackMethod指明如果调用出错就会调用hello方法
@Component
@Service() //暴露服务
public class UserServiceImpl implements UserService {
@HystrixCommand(fallbackMethod = "hello")
public List<UserAddress> getUserAddressList(String userId) {
UserAddress userAddress1 = new UserAddress(1, "温州市1楼", "1", "郑老师", "112233445566", "Y");
UserAddress userAddress2 = new UserAddress(2, "温州市2楼", "2", "昌老师", "778899665544", "Y");
if (Math.random()>0.5){
throw new RuntimeException();
}
return Arrays.asList(userAddress1,userAddress2);
}
public String hello(String name) {
return "hystrix fallback value";
}
}
3、配置Consumer端
@Service
public class OrderServiceImpl implements OrderService {
@Reference
UserService userService;
public List<UserAddress> initOrder(String userId) {
//1、查询用户收货地址
System.out.println("用户id:"+userId);
List<UserAddress> userAddressList = userService.getUserAddressList(userId);
return userAddressList;
}
}