目录

一、Hystrix执行过程

二、Hystrix熔断机制

1. 熔断原理

2. HystrixCircuitBreakerImpl源码解析

3. 熔断器开关状态

4. 采样统计

三、配置参数

四、参考资料


一、Hystrix执行过程

step1:每次调用创建一个新的HystrixCommand,把依赖调用封装在run()方法中。
step2:执行execute()/queue做同步或异步调用。
step3:判断熔断器(circuit-breaker)是否打开,如果打开跳到步骤8,进行降级策略,如果关闭进入步骤。
step4:判断线程池/队列/信号量是否跑满,如果跑满进入降级步骤8,否则继续后续步骤。
step5:调用HystrixCommand的run方法。运行依赖逻辑
        step5a:依赖逻辑调用超时,进入步骤8。
step6:判断逻辑是否调用成功
        step6a:返回成功调用结果
        step6b:调用出错,进入步骤8。
step7:计算熔断器状态,所有的运行状态(成功, 失败, 拒绝,超时)上报给熔断器,用于统计从而判断熔断器状态
step8:getFallback()降级逻辑。
         以下四种情况将触发getFallback调用:
         (1):run()方法抛出非HystrixBadRequestException异常
         (2):run()方法调用超时
         (3):熔断器开启拦截调用
         (4):线程池/队列/信号量是否跑满
        step8a:没有实现getFallback的Command将直接抛出异常
        step8b:fallback降级逻辑调用成功直接返回
        step8c:降级逻辑调用失败抛出异常
step9:返回执行成功结果

二、Hystrix熔断机制

1. 熔断原理

如上图是熔断器的类图,默认类为HystrixCircuitBreakerImpl。以上两个类都是HystrixCircuitBreaker接口的内部静态类。其中HystrixCircuitBreaker.HystrixCircuitBreakerImpl#allowRequest()方法判定是否熔断。如下图所示,若为true,则没有熔断,进入Command#run();false,则进入熔断,Command#进入getFallback()。

2. HystrixCircuitBreakerImpl源码解析

方法名称 作用
boolean allowRequest() 判断是否熔断
boolean allowSingleTest() 允许一段时间窗口内测试服务器是否正常,若成功熔断开关关闭
boolean isOpen() 当前熔断器是否进行熔断(根据统计)
void markSuccess() 熔断器开关关闭后,重置统计数据
package com.netflix.hystrix;import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;import com.netflix.hystrix.HystrixCommandMetrics.HealthCounts;public interface HystrixCircuitBreaker {....../* package */static class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {// 参数配置private final HystrixCommandProperties properties;// 采样统计private final HystrixCommandMetrics metrics;// 熔断器状态:打开或关闭,默认为false,即关闭private AtomicBoolean circuitOpen = new AtomicBoolean(false);// 熔断器打开时的最后一个测试请求的时间戳(尝试关闭熔断器,不能一直打开 _ 自动恢复)private AtomicLong circuitOpenedOrLastTestedTime = new AtomicLong();protected HystrixCircuitBreakerImpl(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {this.properties = properties;this.metrics = metrics;}// 重置采样统计:一段时间窗口内请求成功后public void markSuccess() {// 熔断器处于打开状态if (circuitOpen.get()) {// 尝试关闭熔断器成功if (circuitOpen.compareAndSet(true, false)) {// 重置采样统计metrics.resetStream();}}}// 判断请求是否熔断:true,run();false,getFallback()@Overridepublic boolean allowRequest() {// 熔断开关强制打开,则进入熔断if (properties.circuitBreakerForceOpen().get()) {return false;}// 熔断开关强制关闭,则正常处理if (properties.circuitBreakerForceClosed().get()) {// 处理当前请求,采样统计后,熔断器是否需要打开isOpen();return true;}return !isOpen() || allowSingleTest();}// 一段时间窗口内允许请求(半打开状态)—— 自动恢复public boolean allowSingleTest() {// 熔断器打开时的最后一个测试请求的时间戳long timeCircuitOpenedOrWasLastTested = circuitOpenedOrLastTestedTime.get();// 熔断器打开// 当前时间戳 > 熔断器打开时的最后一个测试请求的时间戳 + 一段时间窗口内(配置获取)if (circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + properties.circuitBreakerSleepWindowInMilliseconds().get()) {// 尝试更新最后一个测试请求的时间戳成功if (circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis())) {// 一段时间窗口内允许请求return true;}}return false;}// 判定当前熔断器是否进行熔断(根据统计)@Overridepublic boolean isOpen() {// 熔断器已经打开if (circuitOpen.get()) {return true;}// 熔断器开关关闭,则根据采样是否需要打开熔断// 健康统计 —— 采样统计类HealthCounts health = metrics.getHealthCounts();// 采样总请求数 < 配置circuitBreakerRequestVolumeThreshold阈值,不熔断if (health.getTotalRequests() < properties.circuitBreakerRequestVolumeThreshold().get()) {return false;}// 采样错误率 < 配置circuitBreakerErrorThresholdPercentage阈值,不熔断if (health.getErrorPercentage() < properties.circuitBreakerErrorThresholdPercentage().get()) {return false;// 采样错误率 > 配置circuitBreakerErrorThresholdPercentage阈值,熔断} else {// 尝试打开熔断器成功if (circuitOpen.compareAndSet(false, true)) {// 设置熔断器打开时的最后一个测试请求的时间戳为当前时间戳circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());return true;} else {// 失败时,也进行熔断return true;}}}}......}

3. 熔断器开关状态

闭合_Closed:强制关闭或闭合状态,不启动熔断,即:不降级处理。

打开_Open:强制打开或打开状态,启动熔断,调用getFallback()。

半打开_Half-Open:打开状态,一段时间窗口内进行重试,成功后开关关闭;否则还处于打开。

4. 采样统计

BucketedCounterStream:计数统计:记录一段时间窗口内的失败、超时、线程拒绝,成功(为一组)。统计时采用N-1组数据统计,第N组刚开始统计时随时间变化。基于时间转滚统计。

RollingConcurrencyStream:最大并发数统计:线程池最大并发数。

RollingDistributionStream:延时百分比统计:记录一段时间窗口内的百分位统计,对N-1组百分比数据排序,P50、P99、P999。

package com.netflix.hystrix;import com.netflix.hystrix.metric.HystrixCommandCompletion;
import com.netflix.hystrix.metric.HystrixThreadEventStream;
import com.netflix.hystrix.metric.consumer.CumulativeCommandEventCounterStream;
import com.netflix.hystrix.metric.consumer.HealthCountsStream;
import com.netflix.hystrix.metric.consumer.RollingCommandEventCounterStream;
import com.netflix.hystrix.metric.consumer.RollingCommandLatencyDistributionStream;
import com.netflix.hystrix.metric.consumer.RollingCommandMaxConcurrencyStream;
import com.netflix.hystrix.metric.consumer.RollingCommandUserLatencyDistributionStream;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.util.HystrixRollingNumberEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.functions.Func0;
import rx.functions.Func2;import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;public class HystrixCommandMetrics extends HystrixMetrics {......public static class HealthCounts {// 请求总数计数private final long totalCount;// 请求失败计数 = 失败 + 超时 + 线程池拒绝 + 信号量拒绝private final long errorCount;// 请求失败错误率private final int errorPercentage;HealthCounts(long total, long error) {this.totalCount = total;this.errorCount = error;if (totalCount > 0) {this.errorPercentage = (int) ((double) errorCount / totalCount * 100);} else {this.errorPercentage = 0;}}private static final HealthCounts EMPTY = new HealthCounts(0, 0);public long getTotalRequests() {return totalCount;}public long getErrorCount() {return errorCount;}public int getErrorPercentage() {return errorPercentage;}// 统计错误数量public HealthCounts plus(long[] eventTypeCounts) {long updatedTotalCount = totalCount;long updatedErrorCount = errorCount;// 成功long successCount = eventTypeCounts[HystrixEventType.SUCCESS.ordinal()];// 失败long failureCount = eventTypeCounts[HystrixEventType.FAILURE.ordinal()];// 超时long timeoutCount = eventTypeCounts[HystrixEventType.TIMEOUT.ordinal()];// 线程池拒绝long threadPoolRejectedCount = eventTypeCounts[HystrixEventType.THREAD_POOL_REJECTED.ordinal()];// 信号量拒绝long semaphoreRejectedCount = eventTypeCounts[HystrixEventType.SEMAPHORE_REJECTED.ordinal()];// 总计 = 成功 + 失败 + 超时 + 线程池拒绝 + 信号量拒绝updatedTotalCount += (successCount + failureCount + timeoutCount + threadPoolRejectedCount + semaphoreRejectedCount);// 错误 = 失败 + 超时 + 线程池拒绝 + 信号量拒绝updatedErrorCount += (failureCount + timeoutCount + threadPoolRejectedCount + semaphoreRejectedCount);return new HealthCounts(updatedTotalCount, updatedErrorCount);}public static HealthCounts empty() {return EMPTY;}public String toString() {return "HealthCounts[" + errorCount + " / " + totalCount + " : " + getErrorPercentage() + "%]";}}
}

三、配置参数

hystrix.command.[commandkey].execution.isolation.strategy:隔离策略THREAD(默认)或SEMAPHORE。
hystrix.command.[commandkey].execution.timeout.enabled:是否开启超时设置,默认true。
hystrix.command.[commandkey].execution.isolation.thread.timeoutInMilliseconds:默认超时时间 ,默认1000ms。
hystrix.command.[commandkey].execution.isolation.thread.interruptOnTimeout:是否打开超时线程中断,默认值true。
hystrix.command.[commandkey].execution.isolation.thread.interruptOnFutureCancel:当隔离策略为THREAD时,当执行线程执行超时时,是否进行中断处理,即Future#cancel(true)处理,默认为false。
hystrix.command.[commandkey].execution.isolation.semaphore.maxConcurrentRequests:信号量最大并发度 默认值10,该参数当使用ExecutionIsolationStrategy.SEMAPHORE策略时才有效。如果达到最大并发请求数,请求会被拒绝。理论上选择semaphore size的原则和选择thread size一致,但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),否则的话应该用thread。 
hystrix.command.[commandkey].fallback.isolation.semaphore.maxConcurrentRequests:fallback方法的信号量配置,配置getFallback方法并发请求的信号量,如果请求超过了并发信号量限制,则不再尝试调用getFallback方法,而是快速失败,默认信号量为10。
hystrix.command.[commandkey].fallback.enabled:是否启用降级处理,如果启用了,则在超时或异常时调用getFallback进行降级处理,默认开启。

hystrix.command.[commandkey].circuitBreaker.enabled:是否开启熔断机制,默认为true。
hystrix.command.[commandkey].circuitBreaker.forceOpen:强制开启熔断,默认为false。
hystrix.command.[commandkey].circuitBreaker.forceClosed:强制关闭熔断,默认为false。
hystrix.command.[commandkey].circuitBreaker.sleepWindowInMilliseconds:熔断窗口时间,默认为5s。
hystrix.command.[commandkey].circuitBreaker.requestVolumeThreshold:当在配置时间窗口内达到此数量后的失败,进行短路。默认20个。
hystrix.command.[commandkey].circuitBreaker.errorThresholdPercentage:出错百分比阈值,当达到此阈值后,开始短路。默认50%。

四、参考资料

Hystrix实现线程隔离_爱我所爱0505-CSDN博客

微服务高可用利器——Hystrix熔断降级原理&实践总结_舒哥的blog-CSDN博客_hystrix熔断原理

熔断机制hystrix - 佳716 - 博客园

服务熔断、线程池和信号量隔离、Feign服务降级项目、数据监控dashboard、Turbine聚合 - 知乎

hystrix熔断器之配置 - zwh1988 - 博客园

Hystrix实现熔断降级相关推荐

  1. 不能再让服务这么任性的被访问啦---分布式服务熔断降级限流利器至Hystrix

    全文概览 文章目录 为什么需要hystrix 特色功能 项目准备 接口测试 业务隔离 线程隔离 信号量隔离 服务降级 触发条件 不足 服务熔断 服务限流 请求合并 HystrixCollapser 工 ...

  2. SpringCloud熔断降级Hystrix详解

    参考文档:https://www.cnblogs.com/qdhxhz/p/9581440.html 一.概念 为什么需要熔断降级? 服务雪崩 多个微服务之间调用的时候,假设微服务A调用微服务B和微服 ...

  3. 微服务高可用利器——Hystrix熔断降级原理实践总结

    前言 最近在工作中参与组内服务稳定性建设,梳理我们目前服务现状并接入公司自研稳定性保障平台.对公司内自研组件以及业界流行的Hystrix做了学习,Netflix Hystrix 里面大量RxJava响 ...

  4. 分布式熔断降级平台aegis

    现状 分布式场景中.若服务不稳定,会导致调用方服务也不可用,从而造成雪崩效应.因此要对在原服务不可用时进行熔断降级处理. 分析 熔断降级可以服务端限流.网关限流.客户端限流. 1. 客户端限流:在调用 ...

  5. php如何做熔断降级,spring cloud 如何实现服务熔断服务降级

    Why 在微服务架构中,由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积.可能导致服务间延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障. 为了维 ...

  6. Spring Cloud Alibaba基础教程:@SentinelResource注解实现限流控制与熔断降级使用详解

    在之前的<使用Sentinel实现接口限流>一文中,我们仅依靠引入Spring Cloud Alibaba对Sentinel的整合封装spring-cloud-starter-alibab ...

  7. 使用.NetCore 控制台演示 熔断 降级(polly)

    1.熔断降级的概念: 熔断:我这里有一根长度一米的钢铁,钢铁的熔点1000度(假设),现在我想用力把这根钢铁折弯,但是人的力有限达不到折弯的点,然后我使用火给钢铁加热,每隔一段时间我就会尝试一下是否能 ...

  8. Sentinel 成为 Spring Cloud 官方推荐的主流熔断降级方案

    近日,Sentinel 贡献的 spring-cloud-circuitbreaker-sentinel  模块正式被Spring Cloud社区合并至 Spring Cloud Circuit Br ...

  9. 面试官:熔断降级原理是什么?

    仅以两张图来初步形容一下 熔断 适用的场景: 雪崩 股灾   什么是熔断 来自 wiki 的 熔断机制 描述: 熔断机制(英语:Circuit breaker / Trading curb)指的是在股 ...

最新文章

  1. 用户界面设计准则从何而来
  2. CocoaPods安装与使用
  3. python计算文件md5值
  4. Linux学习:第一天,
  5. 使用ExtJS创建前端WebQQ界面
  6. jquery的一些小小实例
  7. 为什么mysql默认事务隔离级别为RR
  8. 费曼技巧在学习中的应用
  9. Microk8s单机安装
  10. 布莱克斯科尔斯模型(六)写在最后
  11. js不改变原数组的情况,添加或删除指定的元素
  12. 五十 烤肉之后 我在软件园的那些日子里
  13. N1盒子旁路由教程面向小白啰嗦版
  14. kruskal C++
  15. win10+vs2015+pcl1.8.1安装配置
  16. Sql Server 数据类型
  17. 暴力破解Zip 文件
  18. 源码编译安装部署LNMP架构(Nginx、MYSQL、PHP+论坛)
  19. STM32——CAN控制器原理与配置
  20. vue路由跳转后,刷新指定页面。

热门文章

  1. git版本回退的最佳操作
  2. 【物联网服务NodeJs-5天学习】第四天存储篇④ ——基于MQTT的环境温度检测,升级存储为mysql
  3. 深度学习:长短期记忆模型LSTM
  4. 441_MPLAB X中导入MPLAB工程
  5. Vuex是什么?如何理解和应用?
  6. JAVA梅森旋转随机算法,你没听过的梅森旋转算法
  7. Sitewhere物联网云平台安装
  8. 游戏设计的艺术:一本透镜的书——第十五章 其中一种体验是故事
  9. SpringBoot + Sharding JDBC,一文搞定分库分表、读写分离
  10. 虚拟机解压.rar文件