我是靠谱客的博主 务实抽屉,最近开发中收集的这篇文章主要介绍熔断hystrix,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

 

目录

一、Hystrix说明

1.服务雪崩效应:

2.雪崩原因:

3.雪崩应对策略:

4.解决方案:

二、Hystrix解决方式

1.Circuit Breaker :熔断器,

2.downgrade:降级,fallback

3.Isolation:限流(隔离)

4.asynchronous:异步RPC

三、Hystrix metrics:容错计数

1.Metrics:

四、配置参数说明

1.HystrixCommandProperties:HystrixProperty类型

2.HystrixCollapserProperties:HystrixProperty类型

3.HystrixThreadPoolProperties:

五、Spring cloud hystrix示例

1.熔断:

2.隔离:

六、概念

七、工作原理

1. 隔离:

2. 熔断:

八、流程

九、执行方式


官方文档:https://github.com/Netflix/Hystrix/wiki

转载:

https://blog.csdn.net/weixin_40584932/article/details/80903772

https://blog.csdn.net/wugemao/article/details/80760273

一、Hystrix说明

1.服务雪崩效应:

一种因 服务提供者 的不可用导致 服务调用者 的不可用,并将不可用 逐渐放大 的过程

1) A为服务提供者, B为A的服务调用者, C和D是B的服务调用者. 当A的不可用,引起B的不可用,并将不可用逐渐放大C和D时, 服务雪崩就形成了

2.雪崩原因:

1) 服务提供者不可用

a.硬件故障

a1.硬件损坏造成的服务器主机宕机

a2.网络硬件故障造成的服务提供者的不可访问

b.程序Bug

c.缓存击穿:缓存应用重启, 所有缓存被清空时,以及短时间内大量缓存失效时. 大量的缓存不命中, 使请求直击后端,造成服务提供者超负荷运行,引起服务不可用

d.用户大量请求:在秒杀和大促开始前,如果准备不充分,用户发起大量请求造成服务提供者的不可用

2) 重试加大流量

a.用户重试:用户由于忍受不了界面上长时间的等待,而不断刷新页面甚至提交表单

b.代码逻辑重试:服务调用端的会存在大量服务异常后的重试逻辑

3) 服务调用者不可用

a.同步等待造成的资源耗尽:使用 同步调用 时, 会产生大量的等待线程占用系统资源. 一旦线程资源被耗尽,服务调用者提供的服务也将处于不可用状态, 造成服务雪崩效应产生

3.雪崩应对策略:

1) 流量控制

a.网关限流

因为Nginx的高性能, 目前一线互联网公司大量采用Nginx+Lua的网关进行流量控制, 由此而来的OpenResty也越来越热门.

b.用户交互限流

具体措施:

a21. 采用加载动画,提高用户的忍耐等待时间.

a22. 提交按钮添加强制等待时间机制.

c.关闭重试

2) 改进缓存模式

a.缓存预加载

b.同步改为异步刷新

3) 服务自动扩容

a.AWS的auto scaling

4) 服务调用者降级服务

a.资源隔离:主要是对调用服务的线程池进行隔离.

b.对依赖服务进行分类

依赖服务分为: 强依赖和若依赖. 强依赖服务不可用会导致当前业务中止,而弱依赖服务的不可用不会导致当前业务的中止. 

c.不可用服务的调用快速失败

一般通过 超时机制, 熔断器 和熔断后的 降级方法 来实现

4.解决方案:

1)使用Hystrix预防服务雪崩

2)Netflix的 Hystrix 是一个帮助解决分布式系统交互时超时处理和容错的类库, 它同样拥有保护系统的能力

3)Hystrix的设计原则包括:资源隔离、熔断器、命令模式

二、Hystrix解决方式

Hystrix:通过服务熔断(也可以称为断路)、降级、限流(隔离)、异步RPC等手段控制依赖服务的延迟与失败

1.Circuit Breaker :熔断器,

熔断只是作用在服务调用这一端,只需改consumer端

1)熔断器开关相互转换的逻辑

a.服务的健康状况 = 请求失败数 / 请求总数. 

b.熔断器开关由关闭到打开的状态转换是通过当前服务健康状况和设定阈值比较决定的

b1.关闭时, 请求被允许通过熔断器. 如果当前健康状况高于设定阈值, 开关继续保持关闭. 如果当前健康状况低于设定阈值, 开关则切换为打开状态

b2.打开状态, 经过一段时间后, 熔断器会自动进入半开状态, 这时熔断器只允许一个请求通过. 当该请求调用成功时, 熔断器恢复到关闭状态. 若该请求失败, 熔断器继续保持打开状态, 接下来的请求被禁止通过

c.保证服务调用者在调用异常服务时, 快速返回结果, 避免大量的同步等待

d.在一段时间后继续侦测请求执行结果, 提供恢复服务调用的可能

2)参数设

a.circuitBreaker.requestVolumeThreshold //滑动窗口的大小,默认为20

b.circuitBreaker.sleepWindowInMilliseconds //过多长时间,熔断器再次检测是否开启,默认为5000,即5s钟

c.circuitBreaker.errorThresholdPercentage //错误率,默认50%

每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开

2.downgrade:降级,fallback

1)当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值

3.Isolation:限流(隔离)

1)可在服务端做这个限流逻辑,也可在客户端做

2)采用线程/信号的方式,通过隔离限制依赖的并发量和阻塞扩散

a.线程隔离:

a1.即将每个依赖服务分配独立的线程池进行资源隔离, 从而避免服务雪崩

a2.线上建议线程池不要设置过大,否则大量堵塞线程有可能会拖慢服务器

a3.优点:

a31.使用线程可以完全隔离第三方代码,请求线程可以快速放回

a32.当一个失败的依赖再次变成可用时,线程池将清理,并立即恢复可用,而不是一个长时间的恢复

a33.可以完全模拟异步调用,方便异步编程

a4.缺点:

a41.线程池的主要缺点是它增加了cpu,因为每个命令的执行涉及到排队(默认使用SynchronousQueue避免排队),调度和上下文切换

a42.对使用ThreadLocal等依赖线程状态的代码增加复杂性,需要手动传递和清理线程状态

注:Netflix公司内部认为线程隔离开销足够小,不会造成重大的成本或性能的影响

b.信号隔离:

b1.用于限制并发访问,防止阻塞扩散, 与线程隔离最大不同在于执行依赖代码的线程依然是请求线程(该线程需要通过信号申请)

b2.如果客户端是可信的且可以快速返回,可以使用信号隔离替换线程隔离,降低开销

b3.信号量的大小可以动态调整, 线程池大小不可以

缺点:不能设置超时和实现异步访问,所以,只有在依赖服务是足够可靠的情况下才使用信号量

3)除了HystrixBadRequestException异常之外,所有从run()方法抛出的异常都算作失败,并触发降级getFallback()和断路器逻辑

4)HystrixBadRequestException用在非法参数或非系统故障异常等不应触发回退逻辑的场景

5)参数解释

a.CommandKey:依赖命名

a1.每个CommandKey代表一个依赖抽象,相同的依赖要使用相同的CommandKey名称

a2.依赖隔离的根本就是对相同CommandKey的依赖做隔离.

b.CommandGroupKey:依赖分组

b1.命令分组用于对依赖操作分组,便于统计,汇总

b2.CommandGroup是每个命令最少配置的必选参数,在不指定ThreadPoolKey的情况下,字面值用于对不同依赖的线程池/信号区分

c.ThreadPoolKey:线程池/信号

c1.当对同一业务依赖做隔离时使用CommandGroup做区分,但是对同一依赖的不同远程调用如(一个是Redis一个是http),可以使用HystrixThreadPoolKey做隔离区分

c2.在业务上都是相同的组,但是需要在资源上做隔离时,可以使用HystrixThreadPoolKey区分

d.Request-Cache:请求缓存

d1.重写getCacheKey方法,实现区分不同请求的逻辑

d2.请求缓存可以让(CommandKey/CommandGroup)相同的情况下,直接共享结果,降低依赖调用次数,在高并发和CacheKey碰撞率高场景下可以提升性能

e.SEMAPHORE:信号量隔离

e1.隔离本地代码或可快速返回远程调用(如memcached,redis)可以直接使用信号量隔离,降低线程隔离开销

4.asynchronous:异步RPC

三、Hystrix metrics:容错计数

1.Metrics:

1)Hystrix的Metrics中保存了当前服务的健康状况, 包括服务调用总次数和服务调用失败次数等

2)根据Metrics的计数, 熔断器从而能计算出当前服务的调用失败率, 用来和设定的阈值比较从而决定熔断器的状态切换逻辑

2.1.5之后的滑动窗口实现

1)使用RxJava的Observable.window()实现滑动窗口

四、配置参数说明

1.HystrixCommandProperties:HystrixProperty类型

1)Metrics

a.metricsRollingStatisticalWindowInMilliseconds:统计滚动的时间窗口,默认:5000毫秒(取自circuitBreakerSleepWindowInMilliseconds)

b.metricsRollingStatisticalWindowBuckets:统计窗口的Buckets的数量,默认:10个,每秒一个Buckets统计

c.metrics.rollingPercentile.enabled:是否开启监控统计功能,默认:true

d.metrics.rollingStats.timeInMilliseconds:

e.metrics.rollingStats.numBuckets:

f.metrics.rollingPercentile.timeInMilliseconds:

h.metrics.rollingPercentile.numBuckets:

i.metrics.rollingPercentile.bucketSize:

g.metrics.healthSnapshot.intervalInMilliseconds

h.circuitBreaker.requestVolumeThreshold:断路器请求阈值,熔断器在整个统计时间内是否开启的阀值,默认20。也就是在metricsRollingStatisticalWindowInMilliseconds(默认10s)内至少请求20次,熔断器才发挥起作用

2)Circuit Breaker

a.circuitBreaker.sleepWindowInMilliseconds:断路器休眠时间,熔断时间窗口,默认:5秒.熔断器中断请求5秒后会进入半打开状态,放下一个请求进来重试,如果该请求成功就关闭熔断器,否则继续等待一个熔断时间窗口

b.circuitBreaker.enabled:断路器开关,是否启用熔断器,默认true. 启动

c.circuitBreaker.errorThresholdPercentage:断路器错误请求百分比,默认:50%。当出错率超过50%后熔断器启动

d.circuitBreaker.forceOpen:断路器强制开启,是否强制开启熔断器阻断所有请求,默认:false,不开启。置为true时,所有请求都将被拒绝,直接到fallback

e.circuitBreaker.forceClosed:断路器强制关闭,是否允许熔断器忽略错误,默认false, 不开启

3)Execution

a.execution.isolation.semaphore.maxConcurrentRequests:使用信号量隔离时,命令调用最大的并发数,默认:10

b.execution.isolation.strategy:使用命令调用隔离方式,默认:采用线程隔离,ExecutionIsolationStrategy.THREAD

c.execution.isolation.thread.timeoutInMilliseconds:使用线程隔离时,调用超时时间,默认:1秒

d.executionIsolationThreadPoolKeyOverride:线程池的key,用于决定命令在哪个线程池执行

e.execution.isolation.thread.interruptOnTimeout:使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作.默认:true

f.execution.timeout.enabled:

4)Fallback

a.fallback.isolation.semaphore.maxConcurrentRequests:使用信号量隔离时,命令fallback(降级)调用最大的并发数,默认:10

b.fallback.enabled:是否开启fallback降级策略 默认:true

5)Request Context

a.requestLogEnabled:是否开启请求日志,默认:true

b.requestCacheEnabled:是否开启请求缓存,默认:true

2.HystrixCollapserProperties:HystrixProperty类型

1)maxRequestsInBatch:请求合并是允许的最大请求数,默认: Integer.MAX_VALUE

2)timerDelayInMilliseconds:批处理过程中每个命令延迟的时间,默认:10毫秒

3)requestCache.enabled:批处理过程中是否开启请求缓存,默认:开启

3.HystrixThreadPoolProperties:

1)corePoolSize:配置线程池大小,默认值10个. 建议值:请求高峰时99.5%的平均响应时间 + 向上预留一些即可

2)maxQueueSize:配置线程值等待队列长度,默认值:-1,建议值:-1,表示不等待直接拒绝,测试表明线程池使用直接决绝策略+ 合适大小的非回缩线程池效率最高.所以不建议修改此值。当使用非回缩线程池时,queueSizeRejectionThreshold,keepAliveTimeMinutes 参数无效

3)queueSizeRejectionThreshold:队列大小拒绝阈值

4)keepAliveTimeMinutes

5)metrics.rollingStats.timeInMilliseconds

6)metrics.rollingStats.numBuckets

五、Spring cloud hystrix示例

1.熔断:

只是作用在服务调用这一端,因此只需要改动consumer项目相关代码

1)pom.xml:Feign中已经依赖了Hystrix,所以在maven配置上不用做任何改动

2)application.properties:

# Hystrix配置:Feign中已经依赖了Hystrix,所以在maven配置上不用做任何改动
	feign:
  	  hystrix:
    	    enabled: true

3)**Appliaction.java启动类:

@EnableFeignClients //开启feigin注解

@EnableCircuitBreaker //开启Hystrix

@EnableDiscoveryClient //开启注册中心

@SpringBootApplication //spring-boot启动

注:还可用@SpringCloudApplication代替,@SpringCloudApplication包括以下注解: @Target({ElementType.TYPE}

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@SpringBootApplication

@EnableDiscoveryClient

@EnableCircuitBreaker

        @Bean
	@LoadBalanced
	public RestTemplate restTemplate() {
    		//用于调用"提供者"的方法
    		return new RestTemplate();
	}	

4)controller层:

@GetMapping("/order/{userId}/{orderNo}")
public String findOrder(@PathVariable Long userId, @PathVariable String orderNo) 
             throws InterruptedException {
    		return userConsumerService.findOrder(userId,orderNo);
	}

5)service层:添加fallback属性

String findOrder(Long userId,String orderNo) throws InterruptedException;

6)service impl层:创建回调类

@HystrixCommand(fallbackMethod = "findOrderFallback", commandProperties = {
        //timeoutInMilliseconds 使用线程隔离时,调用超时时间
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")
})
public String findOrder(Long userId,String orderNo) throws InterruptedException {
    	Random random = new Random();
    	sleepRandom = random.nextInt(2000);
    	System.out.println("sleepRandom="+sleepRandom);
    	Thread.sleep(sleepRandom);
    	ConsumerBeehiveUser user = findById(userId);
    	if (user != null) {
        	return user.getUsername() + " 的订单" + orderNo + " 找到啦!sleepRandom="+sleepRandom;
    	}
    	return "用户不存在!sleepRandom="+sleepRandom;
}

public String findOrderFallback(Long userId, String orderNo) {
    	return "订单查找失败!sleepRandom="+sleepRandom;
}

7)查看hystrix状态:

a.查看hystrix基本情况:http://localhost:8002/health

b.查看hystrix详情:http://localhost:8002/hystrix.stream

8)参数说明:

a.快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。

b.请求总数下限:在快照时间窗内,必须满足请求总数下限才有资格根据熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用此时不足20次,即使所有的请求都超时或其他原因失败,断路器都不会打开。

c.错误百分比下限:当请求总数在快照时间窗内超过了下限,比如发生了30次调用,如果在这30次调用中,有16次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%下限情况下,这时候就会将断路器打开。

注:fallback是降级处理

2.隔离:

1)*Application:

@SpringBootApplication
@EnableDiscoveryClient //开启eureka服务
@EnableFeignClients //开启feigin注解
@EnableCircuitBreaker //开启Hystrix  @EnableCircuitBreaker或@EnableHystrix
@EnableHystrixDashboard //开启dashboard图形监控
public class ConsumerBeehiveApplication {
    	@Bean
    	@LoadBalanced
    	public RestTemplate restTemplate() {
        	//用于调用"提供者"的方法
        	return new RestTemplate();
    	}

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

2)controller层:

@GetMapping("/testCircuitBreaker/{id}")
public String testCircuitBreaker(@PathVariable int id) {
    StringBuilder sb = new StringBuilder();
    	for(int i = 0; i < 50; i++) {
        	String result = userConsumerService.testCircuitBreaker(i);
        	System.out.println("testCircuitBreaker controller:"+result);
        	sb.append(result).append("n");
    	}
    	return sb.toString();
}

3)service层:

String testCircuitBreaker(int id);

4)service impl层:

@HystrixCommand(fallbackMethod = "testCircuitBreakerFallback", commandProperties = {
        //errorThresholdPercentage 断路器错误请求百分比
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
})
public String testCircuitBreaker(int id) {
    	if(id % 2 == 0 && id < 10) {   // 直接返回
        	return "consumer testCircuitBreaker "+id;
    	} else {   // 无限循环模拟超时
        	int j = 0;
        	while (true) {
          		j++;
        	}
    	}
}

public String testCircuitBreakerFallback(int id) {
    	String template = restTemplate.
getForObject("http://provider-user/user/testCircuitBreaker/"+id, String.class);
    	return "fallback:"+template;
}

六、概念

服务熔断
       一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施,所以很多地方把熔断亦称为过载保护。很多时候刚开始可能只是系统出现了局部的、小规模的故障,然而由于种种原因,故障影响的范围越来越大,最终导致了全局性的后果。
适用场景:防止应用程序直接调用那些很可能会调用失败的远程服务或共享资源

服务降级:
          当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行

七、工作原理

Hystrix 是一个帮助解决分布式系统交互时超时处理和容错的类库, 它同样拥有保护系统的能力。Netflix的众多开源项目之一。

1. 隔离

           Hystrix隔离方式采用线程/信号的方式,通过隔离限制依赖的并发量和阻塞扩散

1)线程隔离

            Hystrix在用户请求和服务之间加入了线程池。

            Hystrix为每个依赖调用分配一个小的线程池,如果线程池已满调用将被立即拒绝,默认不采用排队.加速失败判定时间。线程数是可以被设定的。

原理:用户的请求将不再直接访问服务,而是通过线程池中的空闲线程来访问服务,如果线程池已满,则会进行降级处理,用户的请求不会被阻塞,至少可以看到一个执行结果(例如返回友好的提示信息),而不是无休止的等待或者看到系统崩溃。

隔离前:

隔离后:

b)信号隔离:

         信号隔离也可以用于限制并发访问,防止阻塞扩散, 与线程隔离最大不同在于执行依赖代码的线程依然是请求线程(该线程需要通过信号申请, 如果客户端是可信的且可以快速返回,可以使用信号隔离替换线程隔离,降低开销。信号量的大小可以动态调整, 线程池大小不可以。

2. 熔断

如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。

熔断器:Circuit Breaker

      熔断器是位于线程池之前的组件。用户请求某一服务之后,Hystrix会先经过熔断器,此时如果熔断器的状态是打开(跳起),则说明已经熔断,这时将直接进行降级处理,不会继续将请求发到线程池。熔断器相当于在线程池之前的一层屏障。每个熔断器默认维护10个bucket ,每秒创建一个bucket ,每个blucket记录成功,失败,超时,拒绝的次数。当有新的bucket被创建时,最旧的bucket会被抛弃。

         熔断器的状态机:

  • Closed:熔断器关闭状态,调用失败次数积累,到了阈值(或一定比例)则启动熔断机制;
  • Open:熔断器打开状态,此时对下游的调用都内部直接返回错误,不走网络,但设计了一个时钟选项,默认的时钟达到了一定时间(这个时间一般设置成平均故障处理时间,也就是MTTR),到了这个时间,进入半熔断状态;
  • Half-Open:半熔断状态,允许定量的服务请求,如果调用都成功(或一定比例)则认为恢复了,关闭熔断器,否则认为还没好,又回到熔断器打开状态;

八、流程

流程说明:

1:每次调用创建一个新的HystrixCommand,把依赖调用封装在run()方法中。

2:执行execute()/queue做同步或异步调用。

3:判断熔断器(circuit-breaker)是否打开,如果打开跳到步骤8,进行降级策略,如果关闭进入步骤。

4:判断线程池/队列/信号量是否跑满,如果跑满进入降级步骤8,否则继续后续步骤。

5:调用HystrixCommand的run方法。运行依赖逻辑

5a:依赖逻辑调用超时,进入步骤8。

6:判断逻辑是否调用成功

6a:返回成功调用结果

6b:调用出错,进入步骤8。

7:计算熔断器状态,所有的运行状态(成功, 失败, 拒绝,超时)上报给熔断器,用于统计从而判断熔断器状态。

8:getFallback()降级逻辑。

  以下四种情况将触发getFallback调用:

 (1):run()方法抛出非HystrixBadRequestException异常

 (2):run()方法调用超时

 (3):熔断器开启拦截调用

 (4):线程池/队列/信号量是否跑满

8a:没有实现getFallback的Command将直接抛出异常

8b:fallback降级逻辑调用成功直接返回

8c:降级逻辑调用失败抛出异常

9:返回执行成功结果

九、执行方式

同步执行:即一旦开始执行该命令,当前线程就得阻塞着直到该命令返回结果,然后才能继续执行下面的逻辑

异步执行:命令开始执行会返回一个Future<T>的对象,不阻塞后面的逻辑,开发者自己根据需要去获取结果。

响应式执行:命令开始执行会返回一个Observable<T> 对象,开发者可以给给Obeservable对象注册上Observer或者Action1对象,响应式地处理命令执行过程中的不同阶段。当调用HystrixCommand的observe()方法,或使用Observable的工厂方法(just(),from())即为响应式执行,这个功能的实现是基于Netflix的另一个开源项目RxJava(https://github.com/Netflix/RxJava)来的,更细节的用法可以参考:https://github.com/Netflix/Hystrix/wiki/How-To-Use#wiki-Reactive-Execution。

 

最后

以上就是务实抽屉为你收集整理的熔断hystrix的全部内容,希望文章能够帮你解决熔断hystrix所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部