Spring Cloud中使用Hystrix实现断路器实践

本文围绕 Spring Cloud Hystrix 断路器展开。介绍了 Hystrix 为解决分布式系统“雪崩效应”而生,能避免级联故障。还阐述了其使用方法,包括依赖导入、启动类注解、接口改动等,定义了处理类,说明了四种 fallback 条件,最后提及 Hystrix Dashboard 监控。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring Cloud Hystrix 断路器

1.Hystrix 由来

多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又在调用其他的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,那么对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,这就是所谓的“雪崩效应”。

那么为了解决“雪崩效应”Hystrix应运而生,Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多服务无法避免会调用失败,比如超时、异常等等,Hystrix能够保证在一个服务出现问题的情况下,不会导致整体服务的失败,避免级联故障,以提高分布式系统的弹性。
所以叫“断路器”。“断路器”是一种开关装置,就好比我们家里的熔断保险丝,当出现突发情况,会自动跳闸,避免整个电路烧坏。那么当某个服务发生故障时,通过 Hystrix,会向调用方返回一个符合预期的、可处理的默认响应(也称备选响应,即fallBack),而不是长时间的等待或者直接返回一个异常信息。这样就能保证服务调用方可以顺利的处理逻辑,而不是那种漫长的等待或者其他故障。

这就叫“服务熔断”,就跟熔断保险丝一个道理。

2.Hystrix 使用

上面介绍了 Hystrix 的基本原理,接下来我们来落地到代码实现

2.1依赖导入

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

2.2启动类注解

在启动类中,需要添加 @EnableCircuitBreaker 注解

@SpringBootApplication
@EnableEurekaClient
@ComponentScan({"com.joy.*","cn.com.joy.*"})
@EnableCircuitBreaker
public class O2OManagementApplication {

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

用@SpringCloudApplication最好,因为该注解包含@EnableCircuitBreaker

@SpringCloudApplication
@EnableFeignClients
@ComponentScan({"com.joy.*","cn.com.joy.*"})
public class O2OManagementApplication {

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

2.3对接口的改动

代码入下:

	@RequestMapping("/view/createCase")
	@HystrixCommand(fallbackMethod ="createCaseFallBack",ignoreExceptions = {NullPointerException.class, ArithmeticException.class},)
	public String viewCreateStore(Model model) throws Exception
	{
		//这里默认查询 所有一级标签
		LabelListFeign labelListFeign = new LabelListFeign();
		labelListFeign.setDataType(1);
		labelListFeign.setName("");
		labelListFeign.setParentId(0);
		List<Map<String,String>> labelInfoLevelOneList = labelManagerService.lable_lableNameList(labelListFeign);
		model.addAttribute("labelInfoLevelOneList", labelInfoLevelOneList);
		return "/case/case_create";
	}
	public String createCaseFallBack(Model model) {
		model.addAttribute("message", "系统异常:NOTICE-SERVICE 服务调用异常!");
		return "../../error/error";
	}

我来分析一下代码:labelManagerService 是Feign 接口,我们使用 Feign 来接口式调用。我们看到,在 viewCreateStore(Model model) 方法上添加了 @HystrixCommand(fallbackMethod = “createCaseFallBack”) 注解,我简单解释一下:

@HystrixCommand 表示该接口开启 hystrix 熔断机制,如果出现问题,就去调用 fallbackMethod 属性指定的 createCaseFallBack 方法,那么往下看,就能看到 createCaseFallBack 方法,我们返回了和上面接口一样的数据结构,只不过都是我们自己搞的默认值而已。

viewCreateStore(Model model) 这个接口中,当labelManagerService调用lable_lableNameList方法异常时就会进入fallback方法中。

自行测试

3定义 Hystrix 处理类

上面介绍了 hystrix 的服务熔断和降级处理,但是有没有发现一个问题,这个 @HystrixCommand 注解是加在 Controller 层的接口方法上的,这会导致两个问题:

第一:如果接口方法很多,那么我是不是要在每个方法上都得加上该注解,而且,针对每个方法,我都要指定一个处理函数,这样会导致 Controller 变得越来越臃肿。

第二:这也不符合设计规范,理论上来说,Controller 层就是 Controller 层,我只管写接口即可。就像上一节介绍的 Feign,也是面向接口的,做均衡处理,我自己定义一个接口专门用来做均衡处理,在 Controller 层将该接口注入即可。那么 hystrix 是否也可以有类似的处理呢?
答案是有的。

3.1定义 Hystrix 处理类

下面是定义 Hystrix 处理类:

/**
 * 统一处理熔断
 * SearchServiceFeignService是Feign接口,所有访问都会走feign接口
 * @author wangjun
 */
@Component
public class SearchClientServiceFallbackFactory implements FallbackFactory<SearchServiceFeignService>{
	
	private  static  final Logger logger = LoggerFactory.getLogger(
			SearchClientServiceFallbackFactory.class);
	
	private  static  final String message = "调用search-service异常";
	
	private  static  final String code = "600";
	//组装返回的参数并写入日志
	public ResponseBean fallbackfaction(Throwable cause) {
		Map<String,Object> data = new HashMap<String, Object>();
		data.put("code", code);
		data.put("page", new HashMap<String, Object>());
		data.put("message", message);
		logger.error("fallback;reason was:",cause);
		return ResponseBean.success(data);
	}
	
	@Override
	public SearchServiceFeignService create(Throwable cause) {
		return new SearchServiceFeignService() {
			
			//后管店铺查询
			@Override
			public ResponseBean searchStoreList(SearchStoreListFeign searchStoreListFeign){
				return fallbackfaction(cause);
			}
			
			...
		};
	}
}

我来分析一下代码,实现了 FallbackFactory 接口后,需要重写 create 方法,还是返回 OrderClientService 接口对象,只不过对这个 feign 客户端做了默认处理。

3.2给 Feign 指定 hystrix

OK,现在 hystrix 是绑定了 Feign 接口了,但是 Feign 接口中的某个方法如果出问题了,它怎么知道找谁去做熔断呢?所以在 Feign 接口也需要绑定一下我们定义的 hystrix 处理类:

@FeignClient(value = "SEARCH-SERVICE", fallbackFactory = SearchClientServiceFallbackFactory.class)
public interface SearchServiceFeignService {
	/**
	 * 店铺列表(后管)
	 * @param searchStoreListFeign
	 * @return
	 * @throws Exception
	 */	@RequestMapping(value="/o2o/searchStoreList",method=RequestMethod.POST)
	public ResponseBean searchStoreList(@RequestBody SearchStoreListFeign searchStoreListFeign)
	throws Exception;
	
	...
}

添加了个 fallbackFactory 属性,指定了自定义的 hystrix 处理类。这样的话,Controller 中的所有方法都可以在 hystrix 里有个默认实现了。
还有要在application.properties开启熔断:

# 开启熔断
feign.hystrix.enabled=true

然后,就自行测试吧。
以上一个配置就够了,遇到项目需要的话。还有其他配置如下,按需配置即可

hystrix.command.default和hystrix.threadpool.default中的default为默认CommandKey

Command Properties
Execution相关的属性的配置:
hystrix.command.default.execution.isolation.strategy 隔离策略,默认是Thread, 可选Thread|Semaphore

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 命令执行超时时间,默认1000ms

hystrix.command.default.execution.timeout.enabled 执行是否启用超时,默认启用true
hystrix.command.default.execution.isolation.thread.interruptOnTimeout 发生超时是是否中断,默认true
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 最大并发请求数,默认10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效。如果达到最大并发请求数,请求会被拒绝。理论上选择semaphore size的原则和选择thread size一致,但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),否则的话应该用thread。
semaphore应该占整个容器(tomcat)的线程池的一小部分。
Fallback相关的属性
这些参数可以应用于Hystrix的THREAD和SEMAPHORE策略

hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests 如果并发数达到该设置值,请求会被拒绝和抛出异常并且fallback不会被调用。默认10
hystrix.command.default.fallback.enabled 当执行失败或者请求被拒绝,是否会尝试调用hystrixCommand.getFallback() 。默认true
Circuit Breaker相关的属性
hystrix.command.default.circuitBreaker.enabled 用来跟踪circuit的健康性,如果未达标则让request短路。默认true
hystrix.command.default.circuitBreaker.requestVolumeThreshold 一个rolling window内最小的请求数。如果设为20,那么当一个rolling window的时间内(比如说1个rolling window是10秒)收到19个请求,即使19个请求都失败,也不会触发circuit break。默认20
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds 触发短路的时间值,当该值设为5000时,则当触发circuit break后的5000毫秒内都会拒绝request,也就是5000毫秒后才会关闭circuit。默认5000
hystrix.command.default.circuitBreaker.errorThresholdPercentage错误比率阀值,如果错误率>=该值,circuit会被打开,并短路所有请求触发fallback。默认50
hystrix.command.default.circuitBreaker.forceOpen 强制打开熔断器,如果打开这个开关,那么拒绝所有request,默认false
hystrix.command.default.circuitBreaker.forceClosed 强制关闭熔断器 如果这个开关打开,circuit将一直关闭且忽略circuitBreaker.errorThresholdPercentage
Metrics相关参数
hystrix.command.default.metrics.rollingStats.timeInMilliseconds 设置统计的时间窗口值的,毫秒值,circuit break 的打开会根据1个rolling window的统计来计算。若rolling window被设为10000毫秒,则rolling window会被分成n个buckets,每个bucket包含success,failure,timeout,rejection的次数的统计信息。默认10000
hystrix.command.default.metrics.rollingStats.numBuckets 设置一个rolling window被划分的数量,若numBuckets=10,rolling window=10000,那么一个bucket的时间即1秒。必须符合rolling window % numberBuckets == 0。默认10
hystrix.command.default.metrics.rollingPercentile.enabled 执行时是否enable指标的计算和跟踪,默认true
hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds 设置rolling percentile window的时间,默认60000
hystrix.command.default.metrics.rollingPercentile.numBuckets 设置rolling percentile window的numberBuckets。逻辑同上。默认6
hystrix.command.default.metrics.rollingPercentile.bucketSize 如果bucket size=100,window=10s,若这10s里有500次执行,只有最后100次执行会被统计到bucket里去。增加该值会增加内存开销以及排序的开销。默认100
hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds 记录health 快照(用来统计成功和错误绿)的间隔,默认500ms
Request Context 相关参数
hystrix.command.default.requestCache.enabled 默认true,需要重载getCacheKey(),返回null时不缓存
hystrix.command.default.requestLog.enabled 记录日志到HystrixRequestLog,默认true

Collapser Properties 相关参数
hystrix.collapser.default.maxRequestsInBatch 单次批处理的最大请求数,达到该数量触发批处理,默认Integer.MAX_VALUE
hystrix.collapser.default.timerDelayInMilliseconds 触发批处理的延迟,也可以为创建批处理的时间+该值,默认10
hystrix.collapser.default.requestCache.enabled 是否对HystrixCollapser.execute() and HystrixCollapser.queue()的cache,默认true

ThreadPool 相关参数
线程数默认值10适用于大部分情况(有时可以设置得更小),如果需要设置得更大,那有个基本得公式可以follow:
requests per second at peak when healthy × 99th percentile latency in seconds + some breathing room
每秒最大支撑的请求数 (99%平均响应时间 + 缓存值)
比如:每秒能处理1000个请求,99%的请求响应时间是60ms,那么公式是:
(0.060+0.012)

基本得原则时保持线程池尽可能小,他主要是为了释放压力,防止资源被阻塞。
当一切都是正常的时候,线程池一般仅会有1到2个线程激活来提供服务

hystrix.threadpool.default.coreSize 并发执行的最大线程数,默认10
hystrix.threadpool.default.maxQueueSize BlockingQueue的最大队列数,当设为-1,会使用SynchronousQueue,值为正时使用LinkedBlcokingQueue。该设置只会在初始化时有效,之后不能修改threadpool的queue size,除非reinitialising thread executor。默认-1。
hystrix.threadpool.default.queueSizeRejectionThreshold 即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝。因为maxQueueSize不能被动态修改,这个参数将允许我们动态设置该值。if maxQueueSize == -1,该字段将不起作用
hystrix.threadpool.default.keepAliveTimeMinutes 如果corePoolSize和maxPoolSize设成一样(默认实现)该设置无效。如果通过plugin(https://github.com/Netflix/Hystrix/wiki/Plugins)使用自定义实现,该设置才有用,默认1.
hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds 线程池统计指标的时间,默认10000
hystrix.threadpool.default.metrics.rollingStats.numBuckets 将rolling window划分为n个buckets,默认10

3.3Hystrix四种fallback条件

1.任务超过了"withExecutionTimeoutInMilliseconds"定义的超时时间;

2.任务抛出了非HystrixBadRequestException的异常;

3.超过了线程池线程/信号量数目;

4.熔断器打开;

4Hystrix Dashboard 监控

除了隔离依赖服务的调用以外,Hystrix 还提供了准实时的调用监控(Hystrix Dashboard),Hystrix 会持续记录所有通过 Hystrix 发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求,有多少成功或者失败等。Spring Cloud 也提供了 Hystrix Dashboard 的整合,对监控内容转化成可视化界面。
由于当前项目没用到有兴趣的可以去看看,在此给出链接:
https://blog.youkuaiyun.com/eson_15/article/details/86673843

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值