什么是Hystrix,阿里技术最终面,遗憾的倒在Hystrix面前!

首发地址什么是Hystrix,阿里技术最终面,遗憾的倒在Hystrix面前 !面试

什么是服务雪崩?

在分布式架构中,很常见的一个情形就是某一个请求须要调用多个服务。sql

如客户端访问 user 服务,而 user 服务须要调用 order 服务,order 服务须要调用 goods 服务,因为网络缘由或者自身的缘由,若是 order 服务或者 goods 服务不能及时响应,user 服务将处于阻塞状态,直到 order 服务 goods 服务响应。数据库

此时如有大量的请求涌入,容器的线程资源会被消耗完毕,致使服务瘫痪。缓存

服务与服务之间的依赖性,故障会传播,形成连锁反应,会对整个微服务系统形成灾难性的严重后果,这就是服务故障的“雪崩”效应。tomcat

1.如图所示,此时的系统正在愉快的运行中。服务器

2.忽然这个时候,goods服务节点的网络发生了故障。goods服务节点瘫痪,goods服务不可用。网络

3.因为good服务瘫痪致使order服务向goods服务发送的请求得不到返回,一直处于阻塞,此时user服务仍然一直 向order服务发送请求,最终致使order服务节点的资源耗尽,order服务节点瘫痪,order服务不可用。架构

4.因为good服务瘫痪致使order服务向goods服务发送的请求得不到返回,一直处于阻塞,此时user服务仍然一直 向order服务发送请求,最终致使order服务节点的资源耗尽,也瘫痪掉。此时user服务向order服务发送的请求一样也得不到返回,而客户端依然源源不断的向user服务节点发送请求,最终user服务节点和order服务节点同样,因为资源耗尽致使服务器瘫痪,user服务也不可用。并发

如上所述,一个服务节点的瘫痪,致使整条链路的服务节点都瘫痪的情形,咱们称之为服务雪崩。app

为何会产生服务雪崩?

流量激增:好比异常流量、用户重试致使系统负载升高;

缓存穿透:假设A为client端,B为Server端,假设A系统请求都流向B系统,请求超出了B系统的承载能力,就会形成B系统崩溃;

程序有Bug:代码循环调用的逻辑问题,资源未释放引发的内存泄漏等问题;

硬件故障:好比宕机,机房断电,光纤被挖断等。

数据库严重瓶颈,好比:长事务、慢sql等。

线程同步等待:系统间常常采用同步服务调用模式,核心服务和非核心服务共用一个线程池和消息队列。若是一个核心业务线程调用非核心线程,这个非核心线程交由第三方系统完成,当第三方系统自己出现问题,致使核心线程阻塞,一直处于等待状态,而进程间的调用是有超时限制的,最终这条线程将断掉,也可能引起雪崩。

有什么办法解决服务雪崩?

当发生突发流量激增的状况下,咱们可使用自动扩容,或者是在负载均衡器中添加服务限流功能

对于缓存穿透形成的服务雪崩问题,能够经过缓存预加载、缓存异步加载等方式来解决。

对于程序bug,emmm...,只能改bug了。

对于数据库查询时间过长致使的服务雪崩能够进行sql优化,硬件升级等。

对于硬件故障形成的服务雪崩, ,跨机房路由,异地多活等方式。

对于不一样的形成服务雪崩的场景,有着不少不一样的解决方案,可是没有一个通用的解决方案能够解决全部的问题。

在经过大量的实践证实,线程同步等待是最多见引起的雪崩效应的场景,此刻,本章节的主人公Hystrix将粉墨登场,咱们将详细介绍如何使用Hystrix作故障隔离,熔断器机制等能够解决依赖服务不可用的问题。

Hystrix总体认知

Hystrix是一个用于处理微服务架构中的服务之间调用故障和容错的开源库。

在微服务架构里,各个服务之间的调用均可能会失败,好比超时、异常等。

Hystrix可以保证在一个依赖出问题的状况下,不会致使整个服务链路全线崩溃,提升微服务架构的可用性。

Hystrix,咱们又称“断路器”,其自己是一种开关装置,当某个服务单元发生故障以后,经过断路器的故障监控(相似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方没法处理的异常,这样就保证了服务调用方的线程不会被长时间、没必要要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

Hystrix设计目标,实现方式

设计目标

(1)对依赖服务调用时出现的调用延迟和调用失败进行控制和容错保护。
(2)阻止某一个依赖服务的故障在整个系统中蔓延,服务A->服务B->服务C,服务C故障了,服务B也故障了,服务A故障了,整个系统所有故障,总体宕机。(3)提供fail-fast(快速失败)和快速恢复的支持。
(4)提供fallback优雅降级的支持。
(5)支持近实时的监控、报警以及运维操做。

实现方式

  1. 经过hystrixCommand或者HystrixObservableCommand来封装对外部依赖的访问请求,这个访问请求通常会运行在独立的线程中。

  2. 对于超出咱们设定的阈(yu)值服务调用,直接进行超时返回,不容许它长时间的阻塞。

  3. 对每个依赖服务进行资源隔离。经过线程池或者是semaphore这两种方式。

  4. 对依赖服务被调用的成功次数,失败次数,拒绝次数,超时次数进行统计。

  5. 若是对某一个依赖服务的调用失败次数超过了一点的阈值,Hystrix自动进行熔断,并在一段时间内对该服务的调用直接进行降级,一段时间后再自动尝试恢复

  6. 当对一个服务调用出现失败、被拒绝、超时、短路等异常状况时,自动调用fallback降级机制。

  7. 对属性和配置的修改提供近实时的支持

Hystrix工做流程

首先咱们看一下管网的Hystrix工做流程图:

下面咱们针对这张图详细解读下Hystrix的工做流程。

1.每次调用都会建立HystrixCommand或者HystrixObservableCommand对象

2.执行execute(observe)或queue(toObservable)作同步\异步调用

3.检查请求结果是否被缓存,若是缓存直接返回

4.检查是否开启了断路器,若是开启直接跳到步骤8

5.检查线程池/信号量是否跑满,若是跑满进入步骤8

6.执行 HystrixObservableCommand.construct() or HystrixCommand.run(),若是执行异常或者调用超时直接跳到步骤8

7.计算断路器状态,全部的运行状态(成功, 失败, 拒绝,超时)上报给断路器,用于统计从而判断断路器状态

8.调用fallback降级机制,经过上述步骤会有(熔断器打开,线程池/信号量跑满,调用超时,调用失败)四种状况会进行降级处理

9.返回依赖请求的真正结果

工做流程详解

第一步,建立HystrixCommand或者HystrixObservableCommand对象

HytrixCommand和HystrixObservableCommand包装了对外部依赖访问的逻辑。

整个流程的第一个步骤就是实例化HystrixCommand或者HystrixObservableCommand对象。

在构造这两个Command对象时,能够经过构造方法传递任何执行过程当中须要的参数。

若是对外部依赖调用只返回一个结果值,那么能够实例化一个HystrixCommand对象。

HystrixCommand command = newHystrixCommand(arg1, arg2);

若是在调用外部依赖时须要返回多个结果值时,能够实例化一个HystrixObservableCommand对象

HystrixObservableCommand command = newHystrixObservableCommand(arg1, arg2);

第二步,执行execute(observe)或queue(toObservable)作同步\异步调用

HystrixCommand主要是使用如下两个命令

execute():同步执行,从依赖的服务返回一个单一的结果对象,或者是在发生错误的时候抛出异常。

queue():异步执行,直接返回一个Future对象,其中包含了服务执行结束时要返回的单一结果对象。

HystrixObservableCommand使用如下两个命令

observe():返回Observable对象,返回 Observable 对象,当即发出请求,在依赖服务响应(或者抛出异常/超时)时,经过注册的 Subscriber 获得返回结果,它是一个Hot Observable。

toObservable():返回Observable对象,但只有在订阅该对象时,才会发出请求,而后在依赖服务响应(或者抛出异常/超时)时,经过注册的 Subscriber 获得返回结果,它是一个Cold Observable。

第三步,检查请求结果是否被缓存,若是缓存直接返回

若当前命令的请求缓存功能是被启用的,而且该命令缓存命中,那么缓存的结果会当即以Observable对象的形式返回。

这个结果缓存的好处为:

一、在同一个请求上下文中,能够减小使用相同参数请求原始服务的开销。
二、请求缓存在步骤5执行以前生效,因此能够有效减小没必要要的线程开销。

第四步,检查是否开启了断路器

在缓存没有被命中时,Hystrix会在执行步骤5以前先检查断路器是否被打开。若是打开了,Hystrix不会执行任何命令执行跳转到步骤8

断路器开关控制条件: 1.对外部依赖调用的次数知足配置的阈值  2.对外部依赖调用发生错误的比率知足配置的阈值

在知足以上两个条件时,断路器打开熔断开关,以后全部对外部依赖调用都将被直接断开。

在开关打开时长超过试探窗口期后,断路器将尝试放行部分外部依赖的调用,

根据试探的结果决定从新开启或者关闭熔断开关。

第五步,检查线程池/信号量是否跑满

咱们知道,Hystrix引入了线程池和信号量两种方式实现资源隔离机制。若是此时命令对应的线程池或队列或信号量已经满了,直接跳转到步骤8。

第六步,执行 HystrixObservableCommand.construct() or HystrixCommand.run()

Hystrix会根据咱们编写的方法来决定采起什么方式去请求依赖服务。

1.HystrixCommand.run()——返回单个响应或抛出异常。

2.HystrixObservableCommand.construct()——返回 Observable 对象来发射多个结果,或经过onError发送错误通知。

若是run()或construct()方法执行时长超过了命令的超时阀值,其线程将抛出一个TimeoutException(或者在一个单独的线程抛出,若是命令没有运行在它本身的线程)。

这种状况下 Hystrix转接到fallback处理逻辑(第8步)。

而且若是该命令没有取消或中断,它将放弃run()或construct()方法最终的返回值。

若是命令没有抛出异常而且返回了响应,Hystrix 将会在执行一些日志记录和度量报告以后返回结果给调用者。

若是是经过run()运行,Hystrix 将返回 Observable 发射单个结果,而后发送一个onCompleted的通知;若是是经过construct()运行,Hystrix 直接返回该方法产生的Observable对象。

第七步,计算断路器状态

Hystrix会将每个依赖服务的调用成功,失败,拒绝,超时,等事件,都会发送给circuit breaker断路器。

HystrixCircuitBreaker经过维护一系列的counter记录外部依赖请求的执行状况。

断路器根据维护的这些信息,在符合触发条件下开启断路功能,在条件合适的时候关闭断路开关。

若是打开了断路器,那么在一段时间内就会直接短路,而后若是在以后第一次检查发现调用成功了,就关闭断路器。

第八步,调用fallback降级机制

经过对上述步骤的详细解读,咱们发现有如下几种状况是会调用fallback降级机制的。
1.断路器打开

2.线程池或者信号量已经满了

3.command执行异常

4.执行超时

在服务降级逻辑中,须要实现一个通用的响应结果,而且该结果的处理逻辑应当是从缓存或是根据一些静态逻辑来获取,而不是依赖网络请求获取。

若是必定要在服务降级逻辑中包含网络请求,那么该请求也必须包装在HystrixCommand或HystrixObservableCommand中,从而造成级联的降级策略。

而最终的降级逻辑必定不是一个依赖网络请求的处理,而是一个可以稳定的返回结果的处理逻辑。

1.在 HystrixCommand 中,在 HystrixCommand.getFallback()方法中提供自定义的回调逻辑,方法返回单个回调值。 

2.在 HystrixObservableCommand 中,在HystrixObservableCommand.resumeWithFallback() 方法中提供自定义的回调逻辑,方法返回一个Observable对象来发射一个或多个降级结果

若是fallback返回告终果,那么Hystrix就会返回这个结果。

对于HystrixCommand,会返回一个Observable对象,其中会发返回对应的结果;

对于HystrixObservableCommand,会返回一个原始的Observable对象。

若是没有实现fallback,或者是fallback抛出了异常,Hystrix会返回一个Observable,可是不会返回任何数据。

不一样的command执行方式,其fallback为空或者异常时的返回结果不一样

1.对于execute(),直接抛出异常

2.对于queue(),返回一个Future,调用get()时抛出异常

3.对于observe(),返回一个Observable对象,可是调用subscribe()方法订阅它时,抛出调用者的onError方法

4.对于toObservable(),返回一个Observable对象,可是调用subscribe()方法订阅它时,抛出调用者的onError方法

第九步,返回依赖请求的真正结果

若是Hystrix命令执行成功,它将以Observable形式返回响应给调用者。根据你在步骤2的调用方式不一样,在返回Observablez以前可能会作一些转换。

execute():经过调用queue()来获得一个Future对象,而后调用get()方法来获取Future中包含的值。

queue():将Observable转换成BlockingObservable,在将BlockingObservable转换成一个Future。

observe():订阅返回的Observable,而且当即开始执行命令的逻辑。

toObservable():返回一个没有改变的Observable,你必须订阅它,它才可以开始执行命令的逻辑。

上述就是整个Hystrix的工做流程,固然没有很深刻的讲解,可是仍是建议多看几遍,我面试的时候碰到好几回让我简述Hystrix工做流程,多看几遍,记在内心,面试不慌。

Hystrix使用框架搭建

固然了,Hystrix也能和Feign 和 Zuul 的集成使用,这些在这里就不赘述了,后续介绍Feign和Zuul的文章中会详细说明。

本文主要介绍HystrixCommand 注解方式的使用。

首先咱们搭建一个HystrixClient项目。

添加配置文件application.properties

新建RestConfiguration类,用来全局配置RestTemplate

新建HystrixController

而后在启动类的上添加@EnableHystrix注解。

改造上一篇万字详解Ribbon架构,针对面试高频题多角度细说Ribbon中提供的OrderService,让代码休眠5秒后在返回。

在HystrixController中的三个方法中分别配置了2000ms,10000ms,10000ms若是没有返回结果,那么将直接回调用咱们指定的fallback。

OrderService

上述三步,基本的Hystrix使用框架就搭建完成了,而后咱们启动上一篇万字详解Ribbon架构,针对面试高频题多角度细说Ribbon中提到的Eureka-Server,并按照上篇文章的启动方式,分别启动OrderServeice的7777,8888,9999三个端口,此时咱们打开 http://localhost:8761/ 页面,咱们发现已经有三个服务名为order-service,端口号分别7777,8888,9999的服务注册了进来。

最后咱们启动HystrixClient启动类,而后咱们先访问设置超时时间为10000ms的 localhost:8088/test2 ,由于咱们在OrderService中设置的休眠时间为3000ms因此能在超时时间内返回请求,因此不用调用fallback。

Hystrix核心配置详解

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 

理论上选择semaphore size的原则和选择thread size一致,但选用semaphore时每次执行的单元要比较小且执行速度快(ms级别),不然的话应该用thread。semaphore应该占整个容器(tomcat)的线程池的一小部分。

Fallback相关配置

hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests 

若是并发数达到该设置值,请求会被拒绝和抛出异常而且fallback不会被调用。默认10。

hystrix.command.default.fallback.enabled 

当执行失败或者请求被拒绝,是否会尝试调用hystrixCommand.getFallback() 。默认true。

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。

ThreadPool 相关属性配置

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设成同样(默认实现)该设置无效。

hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds

线程池统计指标的时间,默认10000。

hystrix.threadpool.default.metrics.rollingStats.numBuckets

将rolling window划分为n个buckets,默认10。

Hystrix容错机制之回退降级‍‍‍‍‍‍‍‍‍

1.什么是降级?

降级,一般指事务高峰期,为了保证核心服务正常运行,须要停掉一些不过重要的业务,或者某些服务不可用时,执行备用逻辑从故障服务中快速失败或快速返回,以保障主体业务不受影响。

Hystrix提供的降级主要是为了容错,保证当前服务不受依赖服务故障的影响,从而提升服务的健壮性。

要支持回退或降级处理,能够重写HystrixCommand的getFallBack方法或HystrixObservableCommand的resumeWithFallback方法。

2.什么状况下才会走降级?

从Hystrix的工做流程图中咱们能够看到如下状况会走降级逻辑。
1.断路器打开
2.线程池或者信号量已经满了
3.command执行异常
4.执行超时

3.回退降级有哪些处理方式?

  1. 快速失败:发生故障后直接抛出,不作处理。

  2. 无声失败:发生故障后,返回无心义内容,如null,空Map等,故障会被屏蔽。

  3. 静态失败:这种配置下,发生故障会返回静态的默认值,如返回值是boolean,则结果为默认true。

  4. Stubbed:这种配置适用于返回值是一个复合对象的情形,发生故障时,会手动建立一个复合对象的实例,实例中每每包含了一些默认值或错误信息。

  5. 依赖缓存:这种状况下,当下层服务故障时,会从缓存中取得以前的旧数据供使用。

  6. 主次模式:这是回退降级的一种特殊使用方法。

主次模式解释:

有时候,咱们可能会遇到这样的场景。针对某个业务,可能会有两种处理方案,A方案高效,可是没有通过规模化测试,不敢保证可靠性。B方案保守,虽然效率较低,可是不会出现。这时候,咱们就能够尝试采用主次模式。主流程基于A方案运行,fallback基于B方案运行。在运行过程当中,如不出错,则一直使用A方案,一时出错,可经过回退降级,迅速切换为B方案,以免问题的不受控扩散。

Hystrix监控系统搭建

什么是Hystrix Dashboard?

Hystrix提供了准实时的调用监控(Hystrix DashBoard),Hystrix会持续的记录经过Hystrix发起的请求的执行信息,以统计报表和图形的形式展现给客户,包括每秒执行多少,请求多少成功,请求失败多少等。

Netflix经过Hystrix-metics-event-stream项目实现了对以上指标的监控,SpringCloud也提供了Hystrix DashBoard的整合,对监控内容转化成可视化的界面,以便于用户可以直接的看到服务和集群的状态,在实际使用中,咱们每每还要结合Turbine来使用。

开始搭建Hystrix Dashboard

Hystrix Dashboard的搭建其实很简单,分为三步:

  1. 建立监控Hystrix Dashboard项目模块

  2. 配置application.yml

  3. 配置启动类

首先咱们建立一个HystrixDashboard项目,配置pom.xml文件以下

配置端口为9001

server.port = 9001

配置启动类,添加@EnableHystrixDashboard注解

启动后访问http://localhost:9001/hystrix只要咱们能看到一只豪猪就说明启动成功了。

 

Hystrix使用总结

本文从介绍服务雪崩引入Hystrix,首先带领你们对Hystrix进行了一个总体认知,而且介绍了Hystrix的设计目标以及实现方式。

而后详细分九步了Hystrix的整个工做流程,而且带领你们实战搭建了Hystrix框架和Hystrix监控系统。

最后详细介绍了Hystrix的核心配置,以及Hystrix的重中之重之回退降级。

Hystrix断路器一样是SpringCloud生态系统中不可缺乏的一环,一样也是面试中常常会出现的高频面试题。

原创不易,若是你们喜欢,赏个分享点赞在看三连吧。和你们一块儿成为这世界上最优秀的人。

相关文章
相关标签/搜索