高可用设计主要体现在如下几方面:
1)监控中心宕机不影响服务的调用,只是会丢失一些统计监控数据
2)注册中心对等集群中,任意一台宕机后,将自动切换到另一台
3)注册中心宕机后,服务提供者和服务消费者仍可通过本地缓存进行通讯
4)服务提供者全部宕机后,服务消费者应用将无法使用,并将无限次重连等待服务提供者恢复
Dubbo 直连
dubbo 直连只要在消费端的服务类中 @Reference 注解上加入 url 属性,指定服务提供者暴露的地址即可。
1)启动 zookeeper,再启动服务提供者和消费者测试,确保没有代码错误。
@Service
public class ConsumerServiceImpl implements ConsumerService {
@Reference(url="127.0.0.1:20880")
ProviderService providerService;
public List<Student> useStuInfo(String sname) {
List<Student> stuList = providerService.getStuList(sname);
System.out.println("------------------调用provider方法完成----------------------");
return stuList;
}
}
2)关闭 consumer 服务,在 @Reference 注解中加入 url 属性,关掉 zookeeper,启动 consumer 服务,发现服务消费者依然可以调用服务提供者提供的方法。
我一开始没启动 zookeeper,直接启动服务提供者和消费者,提供者一直报错重试,消费者报错后直接停了。
先启动一次 zookeeper,进行一次成功的调用后,再配置直连才测试成功
Dubbo 负载均衡
在负载均衡集群中, Dubbo 提供了多种负载均衡策略,默认为 Random 随机调用。
负载均衡策略
1)Random LoadBalance
随机,按权重设置随机概率。
消费端发送一次请求,可能被ABC任意一个服务处理。假如是A处理的,如果另一个请求过来,有可能还是A,也有可能是B,也可能是C。在大量请求下,A B C 处理的请求分别占 1/7 2/7 4/7 。
2)RoundRobin LoadBalance
轮询,按公约后的权重设置轮询比率。
按一定的顺序把请求分发到各服务中。按上图 A B C 的顺序,那么请求被分到各服务的顺序是 A B C B C C C
3)LeastActive LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
哪个服务处理的请求最快就分发到哪个服务去处理。
4)ConsistentHash LoadBalance
一致性 Hash,相同参数的请求总是发到同一提供者。
配置负载均衡策略
- 服务端服务级别
<dubbo:service interface="..." loadbalance="roundrobin" />
- 客户端服务级别
<dubbo:reference interface="..." loadbalance="roundrobin" />
- 服务端方法级别
<dubbo:service interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
- 客户端方法级别
<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
- 注解方式
@Reference(loadbalance = "roundrobin")
ProviderService providerService;
@Service(loadbalance = "roundrobin")
@Component
public class ProviderServiceImpl implements ProviderService {
}
集群容错
容错方案
在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。
1)Failover Cluster
失败自动切换,当出现失败,重试其它服务器 。通常用于读操作,但重试会带来更长延迟。可通过 retries=" " 来设置重试次数(不含第一次)。
2)Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
3)Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
4)Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
5)Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。
6)Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。
集群模式配置
按照以下示例在服务提供方和消费方配置集群模式
<dubbo:service cluster="failsafe" />
或
<dubbo:reference cluster="failsafe" />
服务降级
可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。
向注册中心写入动态配置覆盖规则:
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://127.0.0.1:2181"));
registry.register(URL.valueOf("override://127.0.0.1/com.xiao.service.ProviderService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));
其中:
mock=force:return+null
表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。- 还可以改为
mock=fail:return+null
表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
这个配置可以在监控中心灵活开启关闭,分别是屏蔽和容错
服务降级示例
在服务提供端和消费端的 pom 文件加入 hystrix 依赖,学过 springcloud 的朋友都不陌生。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
在服务提供端的方法上加入 @HystrixCommand 注解,并人为地制造异常
@Service
@Component
public class ProviderServiceImpl implements ProviderService {
@HystrixCommand
public List<Student> getStuList(String sname) {
// 产生的随机数大于 0.5 时抛出异常
if(Math.random() > 0.5) {
throw new RuntimeException();
}
Student stu1 = new Student("01", "张三", 20);
Student stu2 = new Student("05", "张三", 18);
return Arrays.asList(stu1, stu2);
}
}
在服务提供端的启动程序中加入 @EnableHystrix 启用 hystrix
@EnableHystrix
@EnableDubbo
@SpringBootApplication
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class, args);
}
}
在服务消费端的方法上加入 @HystrixCommand 注解,指定降级方法,并编写调用该方法出错后要调用的降级方法,降级方法的返回值和参数要与被原本调用的方法一致
@Service
public class ConsumerServiceImpl implements ConsumerService {
@Reference
ProviderService providerService;
@HystrixCommand(fallbackMethod = "getTipsOrLocaldata")
public List<Student> useStuInfo(String sname) {
List<Student> stuList = providerService.getStuList(sname);
System.out.println("------------------调用provider方法完成----------------------");
return stuList;
}
// 降级方法
public List<Student> getTipsOrLocaldata(String sname) {
System.out.println("------------------调用provider方法出错啦----------------------");
return Arrays.asList(new Student("error", "出错啦", 5), new Student("test", "本地数据", 5));
}
}
在服务提供端的启动程序中加入 @EnableHystrix 启用 hystrix 。
启动 zookeeper,并启动服务提供者和服务消费者,多发送几次 http://localhost:8082/getStus?sname=xiao 请求,可看到返回的不同结果,控制台也打印了不同的信息。