在微服务世界中,服务之间通讯时相当频繁,类似单体服务的方法调用,如果某个微服务中断或无法正常运行,则问题可能会级联到上游服务,造成连锁反应,故障爆炸。Netflix创建了Hystrix库,实现了Circuit Breaker断路器模式以解决这些问题。我们可以使用Spring Cloud Netflix Hystrix断路器来保护微服务免受级联故障的影响。
HYSTRIX断路器能够增强系统的弹性,在微服务无法访问时重试,重试几次后就放弃,也能进行快速失效,不把时间耗费在无谓的等待上,防止故障爆炸。它可提供仪表板dashboard监控实时情况。
首先,将 Hystrix 启动程序添加到目录服务:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>
要启用Circuit Breaker, 请 在入口点类上添加 @EnableCircuitBreaker 注释:
@SpringBootApplication @EnableCircuitBreaker public class CircuitbreakerApplication {
在我们自己的方法上使用 @HystrixCommand 注释,可以控制超时或回退。
我们准备结合前面Feign客户端案例,验证一下断路器如何在重要数据的获取上起到关键作用,为此,需要在pom.xml中还要引入feign、eureka和ribbon依赖包,具体可见前面Feign项目的pom.xml。同时,也将以Ariticile领域模型为案例,假设在获取远程所有Article时出错,我们如何继续业务逻辑?
在实际中涉及到金钱方面的编程都需要额外小心,如果没有底层事务支持,那么我们业务上要进行失败回退处理,为了模拟这一实际场景,首先给Article增加一个price字段,表示每篇文章的价格,我们在消费者这里获取远程生产者所有文章的价格,计算总价,如果获取远程出错,我们就给一个默认价格99.99元,这个数值数值是最大化保证系统自身利益,如同自动柜员机取款时,如果碰到网络问题,最大只能取100元,对于银行损失100元也不是什么大问题,而且这种情况极少发生,同时保证ATM机用户能够正常操作,这样做的好处是,控制了网络故障时发生时最大损失。
下面是我们的消费服务代码:
@Service public class OurConsumerService { @Autowired ConsumerService consumerService; @HystrixCommand(fallbackMethod = "countArticleDefault") public Float countArticle(){ List<Article> articles = consumerService.getAllArticles(); float fee = 0.0f; for (Article article : articles) { fee = fee + article.getPrice(); } return fee; } public Float countArticleDefault(){ return 99.99f; } }
上面代码获取远程ConsumerService,遍历Articles集合,计算总价,如果在获取时出错,则执行下面一个默认方法,直接返回总价为99.99元。ConsumerService代码没有变动,是个Feign客户端:
@FeignClient(name="PengProducerService") public interface ConsumerService { @GetMapping("/articles") List<Article> getAllArticles(); }
现在可以启动注册服务器,启动生产者服务,先为生产者服务准备几条Article数据:
[
{
"id": 1,
"title": "my 第1个 post",
"body": "this is 1body",
"startDate": null,
"price": 1111.11
},
{
"id": 2,
"title": "my 第1个 post",
"body": "this is 1body",
"startDate": null,
"price": 1111.11
},
{
"id": 3,
"title": "my 第2个 post",
"body": "this is 2body",
"startDate": "2018-01-01T00:00:00.000+0000",
"price": 143.45
}
]
然后运行消费者服务,获得结果如下:
##############fee is 2365.67
如果我们将生产者服务关闭,再运行消费者服务,应该是获得默认值:
##############fee is 99.99
总结,使用断路器能够提高我们系统的数据可靠性,依据CAP定理,在存在网络分区P情况下,也就是发生通讯断路了,通讯的两边的数据肯定不一致了,虽然各自都可以使用,那么断路器为我们手工处理这种不一致提供了方便。
Spring Cloud专题