Hystrix熔断原理与实践

hystrix.png

技术需求点:

在SpringCloud+SpringBoot部署的微服务系统中,模拟服务故障,证明Hystrix组件可以保证当服务提供者提供的服务不可用时,调用方可以切换到降级后的执行策略,保持系统服务稳定性,同时介绍Hystrix的算法机制和原理。

Hystrix是一种叫豪猪的动物,身体后半部分长满了圆棘刺,当遇到危险时,通过后退的攻击方式将棘刺插入敌人身体,以保护自己不受伤害。

前言:分布式系统服务雪崩问题

在分布式系统中,多个服务之间通常是通过Rpc远程调用的方式实现的,这种服务依赖的模式可能会带来问题,如果被依赖的服务A挂掉,而调用者B没采取任何防御措施,可能会导致调用者B的所有线程在数秒内处于阻塞状态释放不了,后续请求累积增加,可能导致调用者B瘫痪,服务B瘫痪又会导致B的调用者C瘫痪......最后引起服务雪崩问题。因此,一定的防御措施(降级策略)需要在系统设计时考虑到,当服务调用方发现提供方的服务出现异常时,调用方能够快速切换到预置好的降级策略中。

正常时,调用者(UserRequest)调用Dependency A、H、I、P服务:


图片来源参考文章3.png

当Dependcency I系统出现问题,调用者UserRequest也会阻塞:


图片来源参考文章3.png

在请求量较大时,在数秒内所有线程会阻塞,导致所有资源饱和,系统无法再提供服务。


图片来源参考文章3.png

一.Hystrix基于自反馈调节熔断状态的算法原理

在电路系统中,会有保险丝,当电流过大产热过大时,保险丝会熔断以切断与外部电路的联通。Hystrix充当了保险丝的角色,当请求量过大且请求错误量超过我们设定的阈值时,Hystrix的熔断器会熔断,让调用者服务自动降级以保护服务。自动降级后的服务不会再远程调用依赖方的服务,转向我们的降级策略去执行,比如给个失败页面快速失败,减少调用方的漫长等待。

此外,熔断开启,服务降级后,Hystrix有自动恢复的功能,假如我们设定每次熔断后休眠5秒钟(5秒钟内不调用远程服务),到时间后会自动重试,让20次请求尝试调用远程服务,如果能返回正常结果,就认为服务恢复正常,熔断器自动关闭,服务降级停止。

根据这一过程,Hystrix的状态机分为三种状态:open、closed、half-open,熔断器会在这三种状态之间切换。具体来讲:

  • open:被调用方在一定时间窗内请求错误率大于设定的阈值,被判定为异常,熔断开启,服务降级,调用方执行本地的降级策略,不进行远程调用;
  • closed:被调用服务正常,熔断关闭,调用方远程调用服务。
  • half-open:尝试的中间状态,调用方熔断且在休眠了一段时间后,调用方发起测试性的远程调用,测试被调用者是否正常。

熔断器的开关状态取决于HystrixCommandMetrics对象里面的数据,该对象存储了类似远程接口调用次数,失败次数等数据,以时间窗口的形式统计各维度数据。

二.模拟Hystrix实战

1.pom依赖

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

2.开启Hystrix
在EurekaApplication文件上添加注解@EnableCircuitBreaker开启熔断

@EnableCircuitBreaker//开启熔断
@EnableEurekaClient//开启Eureka客户端
@SpringBootApplication
@EnableFeignClients//开启Feign客户端
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class,args);
    }
}

添加之后,感觉注解越来越多,因此可以合并下。
首先将@EnableEurekaClient替换成@EnableDiscoveryClient,两者的共同点是:都能让注册中心发现自己的服务,区别是@EnableEurekaClient只支持Eureka作为注册中心,而@EnableDiscoveryClient支持其它注册中心,比如consul。
然后将@EnableCircuitBreaker、@EnableEurekaClient、@SpringBootApplication替换成@SpringCloudApplication,看@SpringCloudApplication的代码可以看出,该注解就是集成了前面三个。

image.png

3.调用者接口
对getUsers()方法进行熔断,需要给这个方法写一个对应的fallback方法,当调用提供者服务出现异常时,Hystrix会自动执行fallback的方法。当然,需要给方法指定熔断方法,用@HystrixCommand注解声明,
(如果想给类的所有方法都指定一个熔断方法,使用@DefaultProperties(defaultFallback="getUsersFallback"),需要熔断的方法再加@HystrixCommand才行)。注解里面还可以进行各种Hystrix的配置,例如熔断时间等等,下面再说。

@RestController
public class UserController {

    @Autowired
    private UserFeignService userFeignService;

    @RequestMapping("/consumer")
    @HystrixCommand(fallbackMethod = "getUsersFallback")
    public String getUsers(){
        return userFeignService.getUsers();
    }

    public String getUsersFallback(){
        return "调用的服务出现异常了";
    }
}

其中,UserFeignService的代码如下:

//开启feign客户端,eureka-provider-user微服务的serviceid(唯一)
@FeignClient("eureka-provider")
public interface UserFeignService {

    @RequestMapping("/user")
    public String getUsers();
}

4.被调用者接口

@RestController
public class UserController {

    @RequestMapping("/user")
    public String getUsers(){
        return "provider的User服务";
    }
}

完整的基于Eureka注册中心的微服务搭建过程,请参考SpringCloud+SpringBoot搭建服务注册与调用平台这篇文章。

5.测试结果
当consumer能正常调用provider服务时,


image.png

此时,停掉provider服务,再次调用:


image.png

说明熔断成功,重启provider服务,又可以正常调用了。

6.将熔断放在service层级
上面的熔断方法我们是放在controller层级的,但这给业务带来了极大的耦合,我们希望把service层就提供了熔断服务,controller层只调用即可,出现异常在service层处理掉。我们使用feign组件发起远程调用, 因此,在使用feign组件基础上,我们这样优化:
(1)先创建一个实现类UserFeignFallback implements UserFeignService,

@Component
public class UserFeignFallback implements UserFeignService {

    @Override
    public String getUsers() {
        return "Service层:调用的服务出现异常了";
    }
}

(2)在UserFeignService指定fallback的方法:

@FeignClient(value="eureka-provider",fallback = UserFeignFallback.class)
public interface UserFeignService {

    @RequestMapping("/user")
    public String getUsers();
}

(3)在配置文件中开启feign的hystrix熔断功能:

feign.hystrix.enabled=true

(4)最后把controller的接口改成普通的调用接口即可:

    @RequestMapping("/consumer")
    public String getUsers(){
        return userFeignService.getUsers();
    }

三.什么情况下会触发fallback方法?

引自参考4

事件 描述 触发fallback
EMIT 值传递 NO
SUCCESS 执行完成,没有错误 NO
FAILURE 执行抛出异常 YES
TIMEOUT 执行开始,但没有在允许的时间内完成 YES
BAD_REQUEST 执行抛出HystrixBadRequestException NO
SHORT_CIRCUITED 断路器打开,不尝试执行 YES
THREAD_POOL_REJECTED 线程池拒绝,不尝试执行 YES
SEMAPHORE_REJECTED 信号量拒绝,不尝试执行 YES

四.Hystrix可以配置哪些参数

配置方式有2种,一个是在注解@HystrixCommand属性里面配置(比较麻烦),一个是在配置文件中配置,两种都可以,但在注解中配置的优先级更高,下面是一些常用的配置

  • 超时时间(默认1000ms,单位:ms)
    1.hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
    调用者的配置文件中配置,调用者所有方法的超时时间都是该值
    2.hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutInMilliseconds
    调用者的指定方法中配置,优先级高于上边的全局配置

  • 统计次数
    circuitBreaker.requestVolumeThreshold
    当在配置时间窗口内达到此数量的失败后,进行熔断,默认20个

  • close休眠试间
    circuitBreaker.sleepWindowInMilliseconds
    熔断多久后开始尝试是否恢复,默认5s

  • 出错百分比,
    circuitBreaker.errorThresholdPercentage
    当错误超过该百分比触发熔断,默认50%

  • 线程池核心线程数
    hystrix.threadpool.default.coreSize(默认为10)

后记:Hystrix现状-官方社区已死

Hystrix官网已经不再维护新版本,但是因为其版本较为稳定,现阶段不影响用户对它的正常使用。Hystrix的替代方案有两个:
1.Alibaba Sentinel
Sentinel在阿里内部已经被大规模采用,非常稳定,目前在Spring Cloud的孵化器项目Spring Cloud Alibaba中,是阿里开源的一款断路器实现。

2.Resilience4J
Resilience4J是Hystrix官方推荐的替代方案,是一款轻量级框架,使用简单,并且文档非常清晰、丰富。

Tips:现在我们再来看豪猪这种动物,是不是跟hystrix的机制原理一模一样,当发现各种服务故障(敌人)时,调用fallback方法(倒退)快速失败,提高系统抵御灾害能力,作者不但写出了这么强大的组件,还命名了这么贴切的名字,膜拜!

参考文章:
参考1,原理简介:https://www.jianshu.com/p/b8d3eb0cf721?utm_source=oschina-app
参考2,源码解析:https://www.jianshu.com/p/684b04b6c454
参考3,Hystrix介绍:https://www.cnblogs.com/cjsblog/p/9391819.html
参考4,详细属性配置:https://blog.csdn.net/tongtong_use/article/details/78611225

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容