一、zookeeper 宕机与 dubbo直连
1. 现象
项目运行一段时间后 zookeeper 注册中心宕机,还可以消费 dubbo 暴露的服务。
2. 原因
监控中心宕掉不影响使用,只是丢失部分采样数据
zookeeper宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
注册中心对等集群,任意一台宕掉后,将自动切换到另一台
注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
服务提供者无状态,任意一台宕掉后,不影响使用
服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
高可用:通过设计,减少系统不能提供服务的时间
我们可以通过@Reference 注解的 url属性设置 消费者直连提供者:
@Service
public class OrderServiceImpl implements OrderService {
UserService userService;
@Override
public List<UserAddress> initOrder(String userId) {
System.out.println( "用户id : " + userId );
//查询用户地址
List<UserAddress> addressList = userService.getUserAddressList( userId );
return addressList;
}
}
二、集群下 dubbo 负载均衡配置
1. 类型
在集群负载均衡时,Dubbo 提供了多种均衡策略。
Random LoadBalance
随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance
轮询,按公约后的权重设置轮询比率。
存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActive LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHash LoadBalance
一致性 Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
2. 配置
服务端
@Service(loadbalance = "roundrobin")
客户端
@Reference(loadbalance = "roundrobin")
通常我们是使用Dubbo控制台来调节,如下:
三、服务降级
什么是服务降级 ?
当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。
可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。 向注册中心写入动态配置覆盖规则:
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 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
四、整合hystrix,服务熔断与降级处理
Hystrix 指在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包,以及监控和配置等功能,在springcloud基础中,我写过对Hystrix的使用。下面我们使用Dubbo 和 hystrix 整合一下:
服务提供方
1. pom.xml
<!-- Hystrix的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
2. 主启动类 UserServiceProviderApplication
然后在Application类上增加@EnableHystrix来启用hystrix starter:
@EnableHystrix
@EnableDubbo
@SpringBootApplication
public class UserServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceProviderApplication.class, args);
}
}
3. UserServiceImpl
@Service
@Component
public class UserServiceImpl implements UserService{
//将该方法交给了 Hystrix 代理
@HystrixCommand
@Override
public List<UserAddress> getUserAddressList(String userId) {
List<UserAddress> list = new ArrayList<>();
UserAddress address1 = new UserAddress(1 , "上海市杨浦区xxx路xxx号" , "1" , "王某某","0");
UserAddress address2 = new UserAddress(2 , "上海市徐汇区xxx路xxx号" , "1" , "张某某","1");
list.add( address1 );
list.add( address2 );
//构造不定期访问错误
if(Math.random() > 0.5) {
throw new RuntimeException();
}
return list;
}
}
服务消费方
1. pom.xml
同服务提供者一样添加 Hystrix 的依赖
2. 主启动类
@EnableHystrix
@EnableDubbo
@SpringBootApplication
public class GmallOrderConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(GmallOrderConsumerApplication.class, args);
}
}
3. OrderServiceImpl
@Service
public class OrderServiceImpl implements OrderService {
@Reference
UserService userService;
@HystrixCommand(fallbackMethod = "hello")
@Override
public List<UserAddress> initOrder(String userId) {
System.out.println( "用户id : " + userId );
//查询用户地址
List<UserAddress> addressList = userService.getUserAddressList( userId );
return addressList;
}
public List<UserAddress> hello(String userId) {
return Arrays.asList( new UserAddress( 3, "出错地址", "1", "出错", "出错" ) );
}
}
启动提供者和消费者,访问测试如下: