文档章节

Spring Cloud 断路器-Hystrix

jurson86
 jurson86
发布于 2017/08/25 15:20
字数 2268
阅读 78
收藏 2

前言: 
              在微服务架构中,系统是拆分成一个个的服务单元,各单元间通过服务注册与发现的方式互相依
赖。每个单元都在不同的进程中运行,都是通过远程调用的方式进行通信,这样就有可能因为网络原因或
是依赖服务自身问题出现调用延迟或者故障,而这些问题会直接导致调用方的对外服务也出现延迟,若此
时调用方的请求不断增加,最后就会因依赖方响应慢或者不响应导致调用方等待而形成任务积压,最终导
致自身服务的瘫痪。 
 
为了解决这样的问题,因此产生了断路器的概念。 

 

Hysteria 对Ribbon 的支持 

1、 加入 jar: 
  <dependency> 
    <groupId>org.springframework.cloud</groupId> 
    <artifactId>spring-cloud-starter-hystrix</artifactId> 
  </dependency> 
 
2、 开启断路器服务: 
@EnableCircuitBreaker 

@EnableCircuitBreaker
@EnableFeignClients
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApplication {

	public static void main(String[] args) {
		SpringApplication.run(ConsumerApplication.class, args);
	}
}


 
3、 添加注解: 
@HystrixCommand(fallbackMethod = "getFallback") 
 增加方法: getFallback

@RestController
@RequestMapping(value = "/user", method = RequestMethod.POST)
public class UserController {

	private static final String URL = "http://spring-cloud-provider/api/user/{id}";
	private static final String URL2 = "http://spring-cloud-provider2/api/user/{id}";

	@Autowired
	private RestTemplate restTemplate;

	@HystrixCommand(fallbackMethod = "getFallback", commandProperties = @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE"))
	//@HystrixCommand(fallbackMethod = "getFallback", commandKey="", groupKey="")
	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
	public String get(@PathVariable(value = "id") int id) {
		return restTemplate.getForObject(URL, String.class, id);
	}

	public String getFallback(int id) {
		System.out.println("调用远程接口异常,返回自定义信息");
		return "自定义信息";
	}

	@RequestMapping(value = "/2/{id}", method = RequestMethod.GET)
	public String get2(@PathVariable(value = "id") int id) {
		return restTemplate.getForObject(URL2, String.class, id);
	}

}

 

Hystrix 对 Feign 的支持 

一、 Hystrix 对Feign 的支持 
1、 添加 IUserBiz 的实现类 RcFeignFallback 

@Component 
public class RcFeignFallback implements IUserBiz { 
  @Override 
  public String view1(int id) { 
    return null; 
  } 
  @Override 
  public String view2(int id) { 
    System.out.println("调用远程接口异常,返回自定义信息"); 
    return "system error"; 
  } 
} 

2、 只需要在@FeignClient注解里面添加 fallback属性,如下: 
fallback=RcFeignFallback.class 

@FeignClient(value = "spring-cloud-provider", configuration = RcFeignConfiguration.class, fallback=RcFeignFallback.class)
public interface IUserBiz extends UserService{
	
	@RequestMapping(value = "/api/user/{id}", method = RequestMethod.GET)
	String view1(@PathVariable(name = "id") int id);
	
	@RequestMapping(value = "/api/user/{id}", method = RequestMethod.GET)
	Map<String, Object> view2(@PathVariable(value = "id") int id);*/

}

二、  禁用 Hystrix 
# 在 feign 里面禁用 hystrix 
feign.hystrix.enabled=false 
 

三、  单个应用禁用Hystrix 
在 RcFeignConfiguration 里面配置一个 bean,如下: 
@Bean 
@Scope("prototype") 
public Feign.Builder feignBuilder() { 
  return Feign.builder(); 

四、  配置隔离策略 

# 在 feign 和 Ribbon 里面配置隔离策略(全局配置) 
hystrix.command.default.execution.isolation.strategy=SEMAPHORE 
# 配置单个 
hystrix.command.HystrixCommandKey.execution.isolation.strategy 

说明:HystrixCommandKey在 Ribbon 下面默认为方法名,在 Feign 下面默认为类名#方法名(参数
类型) 

https://github.com/OpenFeign/feign/tree/master/hystrix#group-and-command-keys 

 

Hystrix Dashboard 的使用 【Eureka 添加Dashboard】
 

一、 配置(可以单独部署应用) 
1、 加入依赖 
<dependency> 
    <groupId>org.springframework.cloud</groupId> 
    <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> 
  </dependency> 
 
2、 添加注解 
  @EnableHystrixDashboard 


@EnableHystrixDashboard
@EnableEurekaServer
@SpringBootApplication
public class ServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(ServiceApplication.class, args);
	}
}

二、  演示 
访问:http://localhost:8761/hystrix 
加入:http://localhost:8888/hystrix.stream 
 
访问: 
http://localhost:8888/user/1 
http://localhost:8888/feign/user/1 

 

 

工作流程

(参考:https://github.com/Netflix/Hystrix/wiki/How-it-Works) 
 

1、 创建一个 HystrixCommand 或 HystrixObservableCommand 实例 
第一步就是构建一个 HystrixCommand 或 HystrixObservableCommand 实例来向其它组件发出操作请
求,通过构造方法来创建实例。 
HystrixCommand:返回一个单响应 
HystrixObservableCommand:返回一个观察者发出的响应 
 

2、 执行方法 
这里有 4 个方法,前两个只适用于 HystrixCommand 不适用于 HystrixObservableCommand 
execute():阻塞型方法,返回单个结果(或者抛出异常) 
queue():异步方法,返回一个 Future 对象,可以从中取出单个结果(或者抛出异常) 
observe():返回 Observable 对象 
toObservable():返回Observable 对象 
 
3、 缓存判断 
检查缓存内是否有对应指令的结果,如果有的话,将缓存的结果直接以  Observable 对象的形式返回 
 
4、 断路器判断 
检查 Circuit Breaker 的状态。如果 Circuit  Breaker 的状态为开启状态,Hystrix 将不会执行对应
指令,而是直接进入失败处理状态(图中 8)。如果 Circuit Breaker 的状态为关闭状态,Hystrix 会
继续执行(图 5) 

5、 线程池、任务队列、信号量的检查 
确认是否有足够的资源执行操作指令。当线程池和队列(或者是信号量,当不使用线程池隔离模式的
时候)资源满的时候,Hystrix 将不会执行对应指令并且会直接进入失败处理状态(图 8) 

6、  HystrixObservableCommand.construct() 和 HystrixCommand.run() 
如果资源充足,Hystrix 将会执行操作指令。操作指令的调用最终都会到这两个方法: 
HystrixCommand.run():返回一个响应或者抛出一个异常 
HystrixObservableCommand.construct():返回一个可观测的发出响应(s)或发送一个 onError 通知 
 
如果执行指令的时间超时,执行线程会抛出  TimeoutException 异常。Hystrix 会抛弃结果并直接进
入失败处理状态。如果执行指令成功,Hystrix 会进行一系列的数据记录,然后返回执行的结果。 
 
7、 统计断路器的健康情况 
Hystrix 会根据记录的数据来计算失败比率,一旦失败比率达到某一阈值将自动开启 Circuit Breaker 
 
8、 回退 
如果我们在Command中实现了HystrixCommand.getFallback()方法(或 HystrixObservableCommand. 
resumeWithFallback() 方法,Hystrix 会返回对应方法的结果。如果没有实现这些方法的话,仍然 
Hystrix 会返回一个空的 Observable 对象,并且可以通过 onError 来终止并处理错误。 
调用不同的方法返回不同的结果: 
execute(): 将会抛出异常 
queue(): 将会返回一个Future 对象,如果调用它的 get()方法将会抛出异常 
observe()和 toObservable():都会返回上述的 Observable 对象 
 
9、 返回成功 
如果 Hystrix执行成功,返回的响应取决于在步骤 2 中调用命令。 
execute():阻塞型方法,返回单个结果(或者抛出异常) 
queue():异步方法,返回一个 Future 对象,可以从中取出单个结果(或者抛出异常) 
observe():返回 Observable 对象 
toObservable():返回Observable 对象 
 

工作原理:

断路器开启或者关闭的条件: 
1、 当满足一定的阀值的时候(默认 10 秒内超过 20 个请求次数) 
2、 当失败率达到一定的时候(默认 10 秒内超过 50%的请求失败) 
3、 到达以上阀值,断路器将会开启 
4、 当开启的时候,所有请求都不会进行转发 
5、 一段时间之后(默认是 5 秒) ,这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,
断路器会关闭,若失败,继续开启。重复 4 和5。 

 

Hystrix 的隔离策略 

说明: 
1、  Hystrix 通过舱壁模式来隔离限制依赖的并发量和阻塞扩散 
2、  hystrix 提供了两种隔离策略:线程池隔离(THREAD)和信号量隔离(SEMAPHORE)。 


 一、  线程池隔离(默认策略模式) 
线程池隔离把执行依赖代码的线程与请求线程(如:tomcat 线程)分离,请求线程可以自由控制
离开的时间。 
通过线程池大小可以控制并发量,当线程池饱和时可以提前拒绝服务,防止依赖问题扩散。 
生产环境建议线程池(默认是 10 个线程)不要设置过大,否则大量堵塞线程有可能会拖慢服
务器。 
 
优点: 
1、 使用线程池隔离可以完全隔离第三方应用,请求线程可以快速放回。 
2、 请求线程可以继续接受新的请求,如果出现问题线程池隔离是独立的不会影响其他应用。 
3、 当失败的应用再次变得可用时,线程池将清理并可立即恢复,而不需要一个长时间的恢复。 
4、 独立的线程池提高了并发性。 
 
注意:尽管线程池隔离是由一个单独的线程提供,客户端代码(异常方法里面的请求)应该也
有超时机制,不能让响应的线程无限期等待,应该适时去中断它,阻止 Hystrix线程池的饱和。 

缺点: 
线程池隔离的主要缺点是它们增加计算开销(CPU) 。每个命令的执行涉及到排队、调度和上下文切换都是在一个单独的线程上运行的。 
Netflix在设计这个系统时认为可以接受此开销的费用以换取它提供的好处。 


  题外话: 
Netflix 内部 API 每天 10+亿的 HystrixCommand 依赖请求使用线程隔离,每个应用大约 40 多
个线程池,每个线程池大约 5-20 个线程(大多数都设置为 10)。 
 

二、  信号量隔离 
使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,当请求进来时先判断计数
器的数值,若超过设置的最大线程个数则拒绝该请求,若不超过则通行,这时候计数器+1,请求返
回成功后计数器-1。 
 
与线程池隔离最大不同在于执行依赖代码的线程依然是请求线程 
tips:信号量的大小可以动态调整, 线程池大小不可以 

区别: 

 

 

 

 

 

© 著作权归作者所有

jurson86
粉丝 2
博文 327
码字总数 341542
作品 0
深圳
个人站长
私信 提问
热门技术从零开始学Spring Cloud视频教程发布

使用技术 (1)spring boot,使用版本:1.5.8 (2)spring cloud ,使用版本:Dalston.SR4 (3)Netflix Eureka (4)Netflix Ribbon (5)Feign (6)Netflix Hystrix (7)Spring Clou Con...

小红牛
2018/08/04
0
0
Spring Cloud学习:03断路器(Hystrix)

1 Hystrix介绍 Spring Cloud Hystrix是分布式系统处理超时和错误的机制,如下图所示,分布式系统中某个用户请求依赖A、H、I、P服务。 当此请求并发超过50的时候,服务I处理速度变慢,但是服务...

寒武没有纪
2017/10/22
151
0
疯狂Spring Cloud连载(16)Hystrix运作流程

本文节选自《疯狂Spring Cloud微服务架构实战》 京东购买地址:https://item.jd.com/12256011.html 当当网购买地址:http://product.dangdang.com/25201393.html Spring Cloud教学视频:htt...

杨大仙的程序空间
2017/11/02
547
2
史上最简单的 SpringCloud 教程 | 终章

版权声明:本文为博主原创文章,欢迎转载,转载请注明作者、原文超链接 ,博主地址:http://blog.csdn.net/forezp。 https://blog.csdn.net/forezp/article/details/70148833 转载请标明出处...

方志朋
2017/04/12
0
0
史上最简单的SpringCloud教程 | 第四篇:断路器(Hystrix)

在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。...

方宏春
2018/04/14
152
1

没有更多内容

加载失败,请刷新页面

加载更多

golang-字符串-地址分析

demo package mainimport "fmt"func main() {str := "map.baidu.com"fmt.Println(&str, str)str = str[0:5]fmt.Println(&str, str)str = "abc"fmt.Println(&s......

李琼涛
今天
4
0
Spring Boot WebFlux 增删改查完整实战 demo

03:WebFlux Web CRUD 实践 前言 上一篇基于功能性端点去创建一个简单服务,实现了 Hello 。这一篇用 Spring Boot WebFlux 的注解控制层技术创建一个 CRUD WebFlux 应用,让开发更方便。这里...

泥瓦匠BYSocket
今天
6
0
从0开始学FreeRTOS-(列表与列表项)-3

FreeRTOS列表&列表项的源码解读 第一次看列表与列表项的时候,感觉很像是链表,虽然我自己的链表也不太会,但是就是感觉很像。 在FreeRTOS中,列表与列表项使用得非常多,是FreeRTOS的一个数...

杰杰1号
今天
8
0
Java反射

Java 反射 反射是框架设计的灵魂(使用的前提条件:必须先得到代表的字节码的 Class,Class 类 用于表示.class 文件(字节码)) 一、反射的概述 定义:JAVA 反射机制是在运行状态中,对于任...

zzz1122334
今天
5
0
聊聊nacos的LocalConfigInfoProcessor

序 本文主要研究一下nacos的LocalConfigInfoProcessor LocalConfigInfoProcessor nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/config/impl/LocalConfigInfoProcessor.java p......

go4it
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部