Hystrix - 阻断器

本文阐述了微服务架构中常见的灾难性雪崩效应及其原因,包括服务提供者和调用者的不可用及重试机制的不当使用。提出了降级、隔离、熔断、请求缓存和合并等五种解决方案,详细解析了每种策略的实现方式,如使用Hystrix注解和配置参数。同时介绍了如何通过线程池和信号量进行隔离,以及请求缓存和合并的优缺点。

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

一、什么是灾难性雪崩效应

造成灾难性雪崩效应的原因,可以简单归结为下述三种:
服务提供者不可用。如:硬件故障、程序BUG、缓存击穿、并发请求量过大等。
重试加大流量。如:用户重试、代码重试逻辑等。
服务调用者不可用。如:同步请求阻塞造成的资源耗尽等。
雪崩效应最终的结果就是:服务链条中的某一个服务不可用,导致一系列的服务不可用,最终造成服务逻辑崩溃。这种问题造成的后果,往往是无法预料的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、解决灾难性雪崩效应

解决灾难性雪崩效应的方式通常有: 降级、隔离、熔断、请求缓存、请求合并.
添加maven的jar包

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

通常来说,开发的时候,使用ribbon处理服务灾难雪崩效应,开发的成本低。维护成本高。使用feign技术处理服务灾难雪崩效应,开发的成本较高,维护成本低。

降级

当请求超时、资源不足等情况发生时进行服务降级处理,不调用真实服务逻辑,而是使用快速失败(fallback)方式直接返回一个托底数据,保证服务链条的完整,避免服务雪崩。
在main方法上添加注解@EnableCircuitBreaker
在调用application service相关代码中,增加新的方法注解@HystrixCommand,代表当前方法启用Hystrix处理服务雪崩效应。@HystrixCommand注解中的属性:
fallbackMethod - 代表当调用的application service出现问题时,调用哪个fallback快速失败处理方法返回托底数据。

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
    @HystrixCommand(fallbackMethod = "getFallback")
    @GetMapping("get")
    public String get() {
        return restTemplate.getForObject("http://EUREKA-CLIENT-PROVIDER/get?name=ribbon调用", String.class);
    }

    public String getFallback() {
        return "服务器正忙, 请稍后再试";
    }

隔离

a. 当服务发生问题时,使用技术手段隔离请求,保证服务调用链的完整。隔离分为线程池隔离和信号量隔离两种实现方式
b. 线程池隔离,就是将并发请求量大的部分服务使用独立的线程池处理,避免因个别服务并发过高导致整体应用宕机
①优点:使用线程池隔离可以完全隔离依赖的服务,请求线程可以快速放回。当线程池出现问题时,线程池是完全隔离状态的,是独立的,不会影响到其他服务的正常执行。当崩溃的服务恢复时,线程池可以快速清理并恢复,不需要相对漫长的恢复等待。独立的线程池也提供了并发处理能力。
②缺点:线程池隔离机制,会导致服务硬件计算开销加大(CPU计算、调度等),每个命令的执行都涉及到排队、调度、上下文切换等,这些命令都是在一个单独的线程上运行的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

线程池隔离的实现方式同样是使用@HystrixCommand注解。相关注解配置属性如下:
groupKey - 分组命名,在application client中会为每个application service服务设置一个分组,同一个分组下的服务调用使用同一个线程池。默认值为this.getClass().getSimpleName();
commandKey - Hystrix中的命令命名,默认为当前方法的方法名。可省略。用于标记当前要触发的远程服务是什么。
threadPoolKey - 线程池命名。要求一个应用中全局唯一。多个方法使用同一个线程池命名,代表使用同一个线程池。默认值是groupKey数据。
threadPoolProperties - 用于为线程池设置的参数。其类型为HystrixProperty数组。常用线程池设置参数有:
coreSize - 线程池最大并发数,建议设置标准为:requests per second at peak when healthy * 99th percentile latency in second + some breathing room。 即每秒最大支持请求数*(99%平均响应时间 + 一定量的缓冲时间)。如:每秒可以处理请求数为1000,99%的响应时间为60ms,自定义提供缓冲时间为12ms,那么结果是 1000*(0.060+0.012) = 72。
maxQueueSize - BlockingQueue的最大长度,默认值为-1,即不限制。如果设置为正数,等待队列将从同步队列SynchronousQueue转换为阻塞队列LinkedBlockingQueue。
queueSizeRejectionThreshold - 设置拒绝请求的临界值。默认值为5。此属性是配合阻塞队列使用的,也就是不适用maxQueueSize=-1的情况。是用于设置阻塞队列限制的,如果超出限制,则拒绝请求。不常用。
keepAliveTimeMinutes - 线程存活时间,单位是分钟。默认值为1。
execution.isolation.thread.timeoutInMilliseconds - 超时时间,默认为1000ms。当请求超时自动中断。
execution.isolation.thread.interruptOnTimeout - 是否开启超时中断。默认为TRUE。和上一个属性配合使用。

c. 信号量隔离

设置一个并发处理的最大极值。当并发请求数超过极值时,通过fallback返回托底数据,保证服务完整性。
在这里插入图片描述

信号量隔离同样通过@HystrixCommand注解配置,常用注解属性有:
commandProperty - 配置信号量隔离具体数据。属性类型为HystrixProperty数组,常用配置内容如下:
execution.isolation.strategy - 设置隔离方式,默认为线程池隔离。可选值只有THREAD和SEMAPHORE。
execution.isolation.semaphore.maxConcurrentRequests - 最大信号量并发数,默认为10。

线程池隔离:请求并发大,耗时较长(一般都是计算大,服务链长或访问数据库)时使用线程池隔离。可以尽可能保证外部容器(如Tomcat)线程池可用,不会因为服务调用的原因导致请求阻塞等待。
信号量隔离:请求并发大,耗时短(计算小,服务链段或访问缓存)时使用信号量隔离。因为这类服务的响应快,不会占用外部容器(如Tomcat)线程池太长时间,减少线程的切换,可以避免不必要的开销,提高服务处理效率。

熔断

当一定时间内,异常请求比例(请求超时、网络故障、服务异常等)达到阀值时,启动熔断器,熔断器一旦启动,则会停止调用具体服务逻辑,通过fallback快速返回托底数据,保证服务链的完整。
熔断有自动恢复机制,如:当熔断器启动后,每隔5秒,尝试将新的请求发送给服务提供者,如果服务可正常执行并返回结果,则关闭熔断器,服务恢复。如果仍旧调用失败,则继续返回托底数据,熔断器持续开启状态。
在这里插入图片描述

熔断的实现是在调用远程服务的方法上增加@HystrixCommand注解。当注解配置满足则开启或关闭熔断器。
注解属性描述:
CIRCUIT_BREAKER_ENABLED (“circuitBreaker.enabled”): 是否开启熔断策略。默认值为true。
CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD (“circuitBreaker.requestVolumeThreshold”): 10ms内,请求并发数超出则触发熔断策略。默认值为20。
CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS (“circuitBreaker.sleepWindowInMilliseconds”): 当熔断策略开启后,延迟多久尝试再次请求远程服务。默认为5秒。
CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE(“circuitBreaker.errorThresholdPercentage”): 10ms内,出现错误的请求百分比达到限制,则触发熔断策略。默认为50%。
CIRCUIT_BREAKER_FORCE_OPEN(“circuitBreaker.forceOpen”): 是否强制开启熔断策略。即所有请求都返回fallback托底数据。默认为false。
CIRCUIT_BREAKER_FORCE_CLOSED(“circuitBreaker.forceClosed”): 是否强制关闭熔断策略。即所有请求一定调用远程服务。默认为false。

请求缓存

缓存是指请求缓存。通常意义上说,就是将同样的GET请求结果缓存起来,使用缓存机制(如redis、mongodb)提升请求响应效率。
使用请求缓存时,需要注意非幂等性操作对缓存数据的影响。
请求缓存是依托某一缓存服务来实现的。在案例中使用redis作为缓存服务器,那么可以使用spring-data-redis来实现redis的访问操作。需要在application client相关工程中导入下述依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

在Spring Cloud应用中,启用spring对cache的支持,需要在启动类中增加注解@EnableCaching,此注解代表当前应用开启spring对cache的支持。简言之就是使spring-data-redis相关的注解生效,如:@CacheConfig、@Cacheable、@CacheEvict等。
spring cloud会检查每个幂等性请求,如果请求完全相同(路径、参数等完全一致),则首先访问缓存redis,查看缓存数据,如果缓存中有数据,则不调用远程服务application service。如果缓存中没有数据,则调用远程服务,并将结果缓存到redis中,供后续请求使用。
如果请求是一个非幂等性操作,则会根据方法的注解来动态管理redis中的缓存数据,避免数据不一致。
注意:使用请求缓存会导致很多的隐患,如:缓存管理不当导致的数据不同步、问题排查困难等。在商业项目中,解决服务雪崩效应不推荐使用请求缓存。

请求合并

在一定时间内,收集一定量的同类型请求,合并请求需求后,一次性访问服务提供者,得到批量结果。这种方式可以减少服务消费者和服务提供者之间的通讯次数,提升应用执行效率。
在这里插入图片描述
在这里插入图片描述>>>什么情况下使用请求合并:
在微服务架构中,我们将一个项目拆分成很多个独立的模块,这些独立的模块通过远程调用来互相配合工作,但是,在高并发情况下,通信次数的增加会导致总的通信时间增加,同时,线程池的资源也是有限的,高并发环境会导致有大量的线程处于等待状态,进而导致响应延迟,为了解决这些问题,我们需要来了解Hystrix的请求合并。
通常来说,服务链条超出4个,不推荐使用请求合并。因为请求合并有等待时间。
请求合并的缺点:
设置请求合并之后,本来一个请求可能5ms就搞定了,但是现在必须再等10ms看看还有没有其他的请求一起的,这样一个请求的耗时就从5ms增加到15ms了,不过,如果我们要发起的命令本身就是一个高延迟的命令,那么这个时候就可以使用请求合并了,因为这个时候时间窗的时间消耗就显得微不足道了,另外高并发也是请求合并的一个非常重要的场景。
使用注解@HystrixCollapser来描述需要合并请求的方法,并提供合并方法使用注解@HystrixCommand来描述。当合并条件(@HystrixCollapser)满足时,会触发合并方法(@HystrixCommand)来调用远程服务并得到结果。
@HystrixCollapser注解介绍:
此注解描述的方法,返回值类型必须是java.util.concurrent.Future类型的。代表方法为异步方法。
@HystrixCollapser注解的属性:
batchMethod - 请求合并方法名。
scope - 请求合并方式。可选值有REQUEST和GLOBAL。REQUEST代表在一个request请求生命周期内的多次远程服务调用请求需要合并处理,此为默认值。GLOBAL代表所有request线程内的多次远程服务调用请求需要合并处理。
timerDelayInMilliseconds - 多少时间间隔内的请求进行合并处理,默认值为10ms。建议设置时间间隔短一些,如果单位时间并发量不大,并没有请求合并的必要。
maxRequestsInBatch - 设置合并请求的最大极值,也就是timerDelayInMilliseconds时间内,最多合并多少个请求。默认值是Integer.MAX_VALUE。

Hystrix的全局相关配置

# hystrix.command.default和hystrix.threadpool.default中的default为默认CommandKey,CommandKey默认值为服务方法名,在properties配置中配置格式混乱,如果需要为每个方法设置不同的容错规则,建议使用yml文件配置。

# Command Properties

# Execution相关的属性的配置:
# 隔离策略,默认是Thread, 可选Thread|Semaphore
hystrix.command.default.execution.isolation.strategy=THREAD
#命令执行超时时间,默认1000ms,只在线程池隔离中有效。
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000
# 执行是否启用超时,默认启用true,只在线程池隔离中有效。
hystrix.command.default.execution.timeout.enabled=true
# 发生超时是是否中断,默认true,只在线程池隔离中有效。
hystrix.command.default.execution.isolation.thread.interruptOnTimeout=true
# 最大并发请求数,默认10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效。如果达到最大并发请求数,请求会被拒绝。理论上选择semaphore的原则和选择thread一致,但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),否则的话应该用thread。semaphore应该占整个容器(tomcat)的线程池的一小部分。
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests=10
# 如果并发数达到该设置值,请求会被拒绝和抛出异常并且fallback不会被调用。默认10。只在信号量隔离策略中有效。
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests=10

# Fallback相关的属性
# 当执行失败或者请求被拒绝,是否会尝试调用fallback方法 。默认true
hystrix.command.default.fallback.enabled=true

# Circuit Breaker相关的属性
# 是否开启熔断器。默认true
hystrix.command.default.circuitBreaker.enabled=true
# 一个rolling window内最小的请求数。如果设为20,那么当一个rolling window的时间内(比如说1个rolling window是10毫秒)收到19个请求,即使19个请求都失败,也不会触发circuit break。默认20
hystrix.command.default.circuitBreaker.requestVolumeThreshold=20
# 触发短路的时间值,当该值设为5000时,则当触发circuit break后的5000毫秒内都会拒绝远程服务调用,也就是5000毫秒后才会重试远程服务调用。默认5000
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000
# 错误比率阀值,如果错误率>=该值,circuit会被打开,并短路所有请求触发fallback。默认50
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
# 强制打开熔断器
hystrix.command.default.circuitBreaker.forceOpen=false
# 强制关闭熔断器
hystrix.command.default.circuitBreaker.forceClosed=false

# ThreadPool 相关参数
# 并发执行的最大线程数,默认10
hystrix.threadpool.default.coreSize=10
# BlockingQueue的最大队列数,当设为-1,会使用SynchronousQueue,值为正时使用LinkedBlcokingQueue。该设置只会在初始化时有效,之后不能修改threadpool的queue size,除非reinitialising thread executor。默认-1。
hystrix.threadpool.default.maxQueueSize=-1
# 即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝。
hystrix.threadpool.default.queueSizeRejectionThreshold=20
# 线程存活时间,单位是分钟。默认值为1。
hystrix.threadpool.default.keepAliveTimeMinutes=1

<think>好的,我现在需要回答用户关于断路器模式在分布式系统中的作用和实现原理的问题。首先,我得回顾一下用户提供的引用内容,看看有哪些信息可以直接使用。 根据引用[3],断路器模式在分布式架构中的作用类似于电路中的保险丝。当某个服务发生故障时,断路器会监控到这个故障,并返回错误响应,而不是让调用方长时间等待。这样可以避免线程被长时间占用,防止故障蔓延。这应该是断路器的主要作用。 接着,引用[4]提到Hystrix是Netflix开源的库,用于处理分布式系统的延迟和容错,Spring Cloud集成它来实现断路器模式。这说明Hystrix是一个常见的实现工具,可能需要提到它的基本机制,比如熔断触发条件和恢复机制。 关于实现原理,用户可能想知道断路器是如何工作的。通常,断路器有三种状态:关闭、打开和半开。引用[3]中的故障监控和错误响应对应状态的转换。当失败次数达到阈值,断路器打开,后续请求直接拒绝。之后会进入半开状态尝试恢复。 另外,引用[2]提到分布式锁是协调技术的一部分,虽然和断路器不同,但可能需要注意不要混淆两者的作用。断路器主要是容错,而分布式锁解决同步问题。 现在需要组织回答的结构。首先解释断路器的作用,再说明实现原理,包括状态转换和关键机制。然后结合实际例子,比如Hystrix,说明如何实现。同时需要引用用户提供的引用,确保在适当的地方标注引用标记。 可能的问题点:是否需要详细说明每个状态的具体转换条件?用户可能想知道触发熔断的具体阈值,比如失败率多少。引用中没有具体数字,可能需要保持一般性描述。 另外,用户可能对断路器如何集成到系统中感兴趣,比如通过Hystrix的依赖配置,如引用[4]提到的,可以简要说明。 最后,生成相关问题,考虑用户可能想了解的优化方法、与其他模式的比较、具体框架的使用等。</think>### 断路器模式在分布式系统中的作用与实现原理 #### 一、断路器模式的作用 断路器模式的核心是**提升系统弹性和容错能力**,尤其在分布式系统中,服务间的依赖关系复杂,单个服务故障可能引发雪崩效应。其作用可总结为: 1. **故障隔离与快速失败** 当某个服务调用失败(如超时、异常)达到阈值时,断路器会“熔断”,直接返回预设错误响应(如降级结果),避免线程因等待故障服务而阻塞[^3]。 2. **防止故障扩散** 通过阻断对故障服务的持续调用,保护系统其他部分免受级联故障影响,类似电路中的保险丝机制。 3. **自动恢复尝试** 断路器会周期性检测故障服务是否恢复,逐步恢复流量以验证可用性。 --- #### 二、实现原理与关键机制 断路器通过**状态机**和**监控指标**实现动态控制,其核心流程如下: 1. **三种状态切换** - **关闭(Closed)**:正常状态,请求直接转发至目标服务。 - **打开(Open)**:触发熔断后,所有请求被拒绝,直接返回错误。 - **半开(Half-Open)**:熔断超时后,允许少量请求试探目标服务是否恢复。 ```plaintext [触发熔断条件] → 关闭 → 打开 → [超时] → 半开 → [成功/失败] → 关闭或重新打开 ``` 2. **熔断触发条件** - **错误率阈值**:例如,过去10秒内50%的请求失败。 - **超时阈值**:请求响应时间超过设定阈值(如2秒)。 - **并发量阈值**:高并发场景下触发熔断保护。 3. **恢复机制** - 进入半开状态后,允许部分请求通过。 - 若试探成功,则关闭断路器;否则重新打开。 --- #### 三、实现示例与工具 以 **Hystrix**(Netflix开源库)为例,其实现原理包括: - **线程池隔离**:为每个服务分配独立线程池,避免资源竞争[^4]。 - **降级策略**:熔断时返回缓存数据或默认响应。 - **监控仪表盘**:实时展示服务健康状态。 ```java // Spring Cloud 中 Hystrix 的示例 @HystrixCommand(fallbackMethod = "fallbackMethod") public String callService() { return restTemplate.getForObject("http://service-url", String.class); } public String fallbackMethod() { return "服务暂不可用,请稍后重试"; // 降级响应 } ``` --- #### 四、应用场景 1. **微服务间调用**:如订单服务依赖支付服务时,防止支付服务故障导致订单服务崩溃。 2. **第三方API集成**:避免因外部服务不稳定影响自身系统。 3. **高并发场景**:通过熔断保护核心业务线程资源。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值