在微服务架构当中,根据业务来拆分成一个一个的微服务,服务和服务之间可以相互调用(RPC),Spring Cloud可以用RestTemplate+Ribbon和Feign来实现,为了保证高可用,单个服务会集群部署,由于网络或者自身原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现阻塞,此时如果有大量的请求涌入,Servlet容器就会被消耗完毕,由于服务和服务之间有依赖姓,因此故障会进行传播,从而对整个系统造成灾难性的后果。
为了解决整个问题,就需要断路器。
1、断路器简介
Netflix开源了Hystrix组件,实现了断路器模式,SpringCloud对这一组件进行了整合。 在微服务架构中,一个请求需要调用多个服务是非常常见的,如下图:
较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystric 是5秒20次) 断路器将会被打开。
2、准备工作
本篇文章是基于 Spring Cloud 服务消费者(Feign) 来实现的。
3、在Ribbon当中使用断路器
第一步:添加依赖
在spring-cloud-consumer-ribbon项目当中添加依赖,代码如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
第二步:在入口类Application当中添加注解
在入口类Application添加注解@EnableHystrix
第三步:改造HelloService
改造HelloService类,在sayHelloFromProvider方法上加上@HystrixCommand注解。该注解对该方法创建了熔断器的功能,并指定了fallbackMethod熔断方法,熔断方法直接返回了一个字符串,字符串为"hi,"+name+",sorry,error!",代码如下:
package com.brimen.springcloudconsumerribbon.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "helloError")
public String sayHelloFromProvider(String name) {
return restTemplate.getForObject("http://spring-cloud-provide/hello/gethello?name=" + name, String.class);
}
public String helloError(String name){
return "hi,"+name+",sorry,error!";
}
}
第四步:启动工程
依次启动spring-cloud-eureka、spring-cloud-provide和spring-cloud-consumer-ribbon工程
第五步:访问spring-cloud-consumer-ribbo的接口
打开浏览器,访问:http://localhost:8082/hello/gethello
第六步:关闭spring-cloud-provide工程
关闭spring-cloud-provide工程,再次进行访问:http://localhost:8082/hello/gethello
这说明spring-cloud-provide工程不可用,当spring-cloud-consumer-ribbo调用spring-cloud-provide的接口时,执行失败,因此调用了断路器的方法
4、在Feign当中使用断路器
第一步:在配置文件当中进行配置
Feign当中是自带断路器的,在D版本之后之后,它没有默认打开,需要在配置文件当中进行配置,配置如下:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8080/eureka/ #1
server:
port: 8084
spring:
application:
name: spring-cloud-consumer-feign #2
feign:
hystrix:
enabled: true #3
#1、服务注册中心的地址
#2、服务的名称,作为其它服务调用的服务名
#3、开启断路器
第二步:改造Service接口
package com.brimen.springcloudconsumerfeign.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
@FeignClient(value = "spring-cloud-provide",fallback = HelloHystrixService.class)
public interface HelloService {
@RequestMapping(value = "/hello/gethello",method = RequestMethod.GET)
String sayHelloFromProvider(@RequestParam(value = "name") String name);
}
创建一个回调的类HelloHystrixService
package com.brimen.springcloudconsumerfeign.service;
import org.springframework.stereotype.Component;
@Component
public class HelloHystrixService implements HelloService {
@Override
public String sayHelloFromProvider(String name) {
return "hi,"+name+",sorry,error!";
}
}
第三步:启动程序并访问
依次启动spring-cloud-eureka、spring-cloud-provide和spring-cloud-consumer-feign
访问spring-cloud-consumer-feign的接口:http://localhost:8084/hello/gethello
结果如下:
结果:在spring-cloud-provide能访问的情况下,能够正常访问到接口并收到数据
第四步:将spring-cloud-provide服务关闭
重新访问http://localhost:8084/hello/gethello,发现断路器已经起作用,调用的是HelloHystrixService里面的回调方法。