1 . 断路器概念

    上篇文中我们完成了一个最简单的一个微服务注册与调用的项目 , 但这是远远不够的 . 在实际的微服务架构中 , 通常是根据业务来拆分成一个个的服务 , 服务与服务之间可以相互调用(RPC) , 在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用 . 为了保证其高可用 , 单个服务通常会集群部署(如我们demo中的service-hello和sevice-hello-a) . 由于网络原因或者自身的原因 , 服务并不能保证100%可用 , 如果单个服务出现问题 , 调用这个服务就会出现线程阻塞 . 此时若有大量的请求涌入 , Servlet容器的线程资源会被消耗完毕 , 导致服务瘫痪 . 服务与服务之间的依赖性 , 故障会传播 , 会对整个微服务系统造成灾难性的严重后果 , 这就是服务故障的"雪崩"效应 . 

    断路器(Circuit Breaker)模式就是为了防止在分布式系统中出现这种雪崩式的连锁反应导致的灾难 . 

    "断路器"本身是一种开关装置 , 用于在电路上保护线路过载 , 一旦某个电器出问题 , 为了防止灾难 , 电路的保险丝就会熔断 . 断路器类似于电路的保险丝 ,  实现思路非常简单 , 可以将需要保护的远程服务调用用封装起来 , 在内部监听失败次数 , 一旦失败次数达到某阀值后(5秒之内发生20次失败是Hystrix定义的缺省值) , 所有后续对该服务的调用 , 断路器截获后都直接返回错误到调用方 , 而不会继续调用已经出问题的服务 , 从而达到保护调用方的目的 .

    在Spring Cloud中使用了Hystrix来实现断路器的功能 . Hystrix是Netflix开源的微服务框架套件之一 , 该框架目标在于通过控制那些访问远程系统、服务和第三方库的节点 , 从而对延迟和故障提供更强大的容错能力 . Hystrix具备拥有回退机制和断路器功能的线程和信号隔离 , 请求缓存和请求打包 , 以及监控和配置等功能 . 

2 . 在ribbon中使用断路器

2.1 改造client-ribbon的代码 , 在pom.xml文件中加入spring-cloud-starter-hystrix的起步依赖
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-hystrix</artifactId>
	<version>1.4.4.RELEASE</version>
</dependency>
2.2 ClientRibbonApplication启动类上加@EnableHystrix注解开启Hystrix
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
public class ClientRibbonApplication {//...}
2.3 改造HelloController , 在hello方法上加上@HystrixCommand注解。该注解对该方法创建了熔断器的功能,并指定了fallbackMethod熔断方法,熔断方法直接返回了一个字符串
@RestController
public class HelloController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/hello")
    @HystrixCommand(fallbackMethod = "helloError")
    public String hello(@RequestParam String id) {
        return restTemplate.getForObject("http://service-hello/hello?id=" + id, String.class);
    }

    public String helloError(String id){
        return "hello " + id + " , error ! " ;
    }
}
2.4 依次启动eurekaserver , service-hello , client-ribbon服务 , 访问 http://localhost:8910/hello?id=123 , 得到正常结果
hello 123 , service-hello , I am from port:8900

然后关闭service-hello , 再访问页面 , 得到如下结果

hello 123 , error !

这就说明当service-hello服务不可用的时候 , service-ribbon调用service-hello的API接口时 , 会执行快速失败 , 直接返回一组字符串 , 而不是等待响应超时 , 这很好的控制了容器的线程阻塞 . 


3 . 在feign中使用断路器

3.1 Feign是自带断路器的,在D版本的Spring Cloud中,它没有默认打开。需要在配置文件中配置打开它,在配置文件加以下代码:
feign:
  hystrix:
    enabled: true
3.2 基于client-feign工程进行改造 , 只需要在IFeignClientService接口的注解中加上fallback的指定实现类就行了
@Component
@FeignClient(value = "service-hello" , fallback = FeignClientServiceCallBack.class) //这里的name对应调用服务的spring.applicatoin.name
public interface IFeignClientService {

    @RequestMapping(value = "/hello")
    String hello(@RequestParam("id") String id);
}
3.3 FeignClientServiceCallBack需要实现IFeignClientService接口 , 并添加注解注入到Ioc容器中(注意 : 这里接口与其实现类都需要添加注解)
@Service
public class FeignClientServiceCallBack implements IFeignClientService{
    @Override
    public String hello(String id) {
        return "hello " + id + " , error ! " ;
    }
}
3.4 同样的 , 关闭service-hello , 启动client-feign项目 , 访问 http://localhost:8911/hello?id=123 , 可以看到如下结果
hello 123 , error !