在微服务架构中,存在那么多的服务单元,若一个单元出现故障(由于网络原因或者自身原因),就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定。为了解决这样的问题,产生了断路器等一系列的服务保护机制。(A服务调用B服务,B服务由于自身处理逻辑等原因造成响应缓慢,会导致A服务线程被挂起,以等待B服务执行,在高并发情况下,这些挂起的线程会导致后面调用A服务的请求被阻塞,最终导致A服务也不可用)。

  加入断路器后,当服务不可用时,通过断路器的故障监控,会直接执行回调函数,直接返回一串字符串,而不是等待响应超时,这样就不会使得线程调用故障服务被长时间占用不释放,从而避免了故障在分布式系统中的蔓延。

    本节内容在上节内容基础上,阅读此节之前,先看上节Spring Cloud之Eureka、Ribbon

一、无断路器示例

  启动上节的eureka-server、service-hello(8081/8082)、ribbon-consumer工程

  在未加入断路器之前,关闭8081实例,发送GET请求到http://localhost:9000/ribbon-consumer,轮询8081/8082,当轮询到8081后(因为8081实例被关)会得到下面输出:

二、加入断路器示例

  在ribbon-consumer工程的pom.xml引入下面依赖

        <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

  在ribbon-consumer工程的 主类ConsumerApplication中使用@EnableCircuitBreaker注解开启断路器功能

package com.stonegeek;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate; /**
* Created by StoneGeek on 2018/5/28.
* 博客地址:http://www.cnblogs.com/sxkgeek
*/
@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class RibbonConsumerApplication { @Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class, args);
}
}

  改造服务消费方式,新增HelloService类,注入RestTemplate实例,然后将在ConsumerController中对RestTemplate的使用迁移到helloService函数中,最后,在helloService函数上增加@HystrixCommand注解来指定回调方法:

package com.stonegeek.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; import java.util.logging.Logger; /**
* Created by StoneGeek on 2018/5/29.
* 博客地址:http://www.cnblogs.com/sxkgeek
*/
@Service
public class HelloService {
private final Logger logger =Logger.getLogger(String.valueOf(getClass()));
@Autowired
RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "helloFallback")
public String helloService(){
//加logger更清晰的看出执行时间
long start =System.currentTimeMillis();
String result=restTemplate.getForEntity("http://SERVICE-HELLO/hello",String.class).getBody();
long end=System.currentTimeMillis();
logger.info("Spend time:"+(end-start));
return result;
} public String helloFallback(){
return "error";
} }

  修改RibbonConsumerApplication.class

package com.stonegeek.controller;

import com.stonegeek.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; /**
* Created by StoneGeek on 2018/5/28.
* 博客地址:http://www.cnblogs.com/sxkgeek
*/
@RestController
public class ConsumerController {
/**
* @Author: StoneGeek
* @Date: 2018/5/29
* @Description:之前不加断路器代码
*/
// @Autowired
// RestTemplate restTemplate;
//
// @RequestMapping(value = "/ribbon-consumer",method = RequestMethod.GET)
// public String helloConsumer(){
// return restTemplate.getForEntity("http://SERVICE-HELLO/hello",String.class).getBody();
// } /**
* @Author: StoneGeek
* @Date: 2018/5/29
* @Description: 加了断路器代码
*/ @Autowired
HelloService helloService; @RequestMapping(value = "/ribbon-consumer",method = RequestMethod.GET)
public String helloConsumer(){
return helloService.helloService();
} }

  此时重新来验证一下断路器实现的服务回调逻辑,此时断开8081实例,当服务消费者轮询到8081时,不再是之前的错误内容,Hystrix服务回调生效

三、模拟服务阻塞来验证断路器回调

  Hystrix默认超时时间是2000毫秒

  我们对service-hello的/hello接口做一些修改(重点是Thread.sleep()函数的使用):

package com.stonegeek.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger; /**
* Created by StoneGeek on 2018/5/27.
* 博客地址:http://www.cnblogs.com/sxkgeek
*/
@RestController
public class HelloController {
private final Logger logger =Logger.getLogger(String.valueOf(getClass()));
@Autowired
private DiscoveryClient client; /**
* @Author: StoneGeek
* @Date: 2018/5/29
* @Description:不加线服务塞的代码
*/
// @RequestMapping(value = "hello",method = RequestMethod.GET)
// public String index(){
// ServiceInstance instance=client.getLocalServiceInstance();
// logger.info("/hello, host:"+instance.getHost()+", service_id:"+instance.getServiceId()+"service_port:"+instance.getPort());
// return "hello world ";
// } /**
* @Author: StoneGeek
* @Date: 2018/5/29
* @Description: 加了Thread.sleep(3000)的服务阻塞代码,由于Hystrix默认超时时间为2000毫秒,
* 所以这里采用了0至3000的随机数以让处理过程有一定概率发生超时来触发断路器
*/ @RequestMapping(value = "/hello",method = RequestMethod.GET)
public String index() throws InterruptedException {
ServiceInstance instance=client.getLocalServiceInstance();
int sleepTime=new Random().nextInt();
logger.info("sleepTime:"+sleepTime);
Thread.sleep(sleepTime);
logger.info("sleepTime:"+sleepTime+"/hello, host:"+instance.getHost()+", service_id:"+instance.getServiceId()+"service_port:"+instance.getPort());
return "hello world ";
}
}

   重新启动service-hello和ribbon-consumer模块,连续访问http://localhost:9000/ribbon-consumer几次,当RIBBON-CONSUMER的控制台输出的Spend time大于2000的时候,网页就会返回error,即服务消费者因调用的服务超时从而触发熔断请求,并调用回调逻辑返回结果

  此时Spring Could Hystrix的断路器就配置完成了!!!

  

最新文章

  1. 在Ubuntu X64上编译Hadoop
  2. XML语言基础2 DTD
  3. win10中将默认输入法设置为英文
  4. Linux 安装tomcat
  5. 转载:第六弹!全球首个微信小程序(应用号)开发教程!通宵吐血赶稿!
  6. ApplicationContext.xml 的最终xml声明,包括注解 aop
  7. c语言typedef与define的相同
  8. MAVEN项目,Eclipse启动报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
  9. ios控制器生存周期
  10. Map Task内部实现分析
  11. 解析XML的方法
  12. Html5视频播放器-VideoJS+Audio标签实现视频,音频及字幕同步播放
  13. linux和Windows下用sublime text3编译运行C,C++
  14. jQuery与js例子
  15. 编译openssl失败(SLES11.3), undefined reference to `OPENSSL_cpuid_setup&#39;
  16. vue中watch的详细用法
  17. 2018-2019 ACM-ICPC Brazil Subregional Programming Contest
  18. oracle 如何创建只有查询权限的用户
  19. JavaScript快速检测浏览器对CSS3特性的支持情况
  20. Eclipse上配置btm

热门文章

  1. webhook 自动部署代码
  2. MySQL Explain学习笔记
  3. [币严区块链]简单易懂的以太坊(ETH)智能合约开发入门教程
  4. .Net基础篇_学习笔记_第三天_Convert类型转换
  5. 深入理解Three.js中透视投影照相机PerspectiveCamera
  6. 6.Sentinel源码分析—Sentinel是如何动态加载配置限流的?
  7. WebStorm2017.3.4版本 注册码
  8. JQuery对于动态生成的标签绑定事件失效
  9. 要不要学习Git(分布式版本控制系统)
  10. 基于操作系统原理的Linux 的用户管理