Spring Cloud Hystrix java
工做流程图:缓存
流程说明:并发
1.每次调用建立一个新的HystrixCommand或HystrixObservableCommand把依赖调用封装在run()方法中.异步
HystrixCommand 用在依赖的服务返回单个操做结果的时候ide
HystrixObservableCommand 用在依赖的服务返回多个操做结果的时候ui
2.执行execute()/queue作同步或异步调用.spa
execute():同步执行,从依赖的服务返回一个单一的结果对象,或是发生错误的时候抛出异常线程
@HystrixCommand(fallbackMethod = "helloFallBack") public String helloService() { return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody(); }
queue():异步执行,直接返回一个Future对象,其中包含了服务执行结束时要返回的单一结果对象。3d
@HystrixCommand(fallbackMethod = "helloFallBack") public Future<String> helloServiceAsync() { return new AsyncResult<String>() { @Override public String invoke() { return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody(); } }; }
Future提供的方法:rest
get() 该方法阻塞当前,等待计算完成,获取返回结果。
isDone () 若是此任务完成返回true
isCancelled() 任务完成前被取消返回true
cancel(false) 取消任务,未开始或已完成返回false,参数表示是否中断执行中的线程 (true中断,false不中断)
3.结果是否被缓存
若当前请求的方法缓存功能时被启动的,而且该方法命中了缓存,直接返回缓存中的数据
ps:Hystrix中的缓存功能,须要初始化HystrixRequestContext = HystrixRequestContext. initializecontext (),每次发起Request时初始化,须要设置一个Filter。以下源码中:HystrixRequestContext是ThreadLocal的,也就是说在一次请求中 屡次调用依赖服务 这个时候缓存功能才有实际意义。若是同时发送两个请求,也是会调用两次依赖服务的。
private static ThreadLocal<HystrixRequestContext> requestVariables = new ThreadLocal<HystrixRequestContext>(); public static boolean isCurrentThreadInitialized() { HystrixRequestContext context = requestVariables.get(); return context != null && context.state != null; }
4.判断熔断器(circuit-breaker)是否打开,若是打开跳到步骤8,进行降级策略,若是关闭进入第五步骤,检查是否有可用的资源来执行命令.
判断断路器的打开/关闭状态,详细逻辑以下:
AtomicBoolean circuitOpen(断路器是否打开的标识,默认fasle),若是打开标识为true,标识断路器是打开状态,若是打开直接走降级策略fallBack(),不然就从度量指标对象 (HystrixCommandMetrics 用来记录各种度量指标的对象)中获取HealthCounts统计对象作进一步判断(该对象记录了一个滚动时间窗内的请求信息快照,默认时间窗为10 S)。
打开熔断器须要知足下面两个条件:
1:若是它的请求总数(QPS)在预设的阀值范围内就返回false,标识熔断器处于未打开状态,该阀值的的配置参数为:hystrix.command.default.circuitBreaker.requestVolumeThreshold=20默认值20
2:若是错误百分比在阀值范围内就返回false,表示断路器处于未打开状态,该阀值的配置参数为:
hystrix.command.default.circuitBreaker.errorThresholdPercentage=50
若是在滚动时间窗内,请求数量超过requestVolumeThreshold的阀值的前提下,若是错误请求数的百分比超过50%,就把断路器设置为打开状态,不然就设置为关闭状态。
这里不得不提另外一个参数:hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000 默认值5000,该属性用来设置当断路器打开以后的休眠时间窗,休眠时间结束后,断路器置为“半开”状态,此时再有请求过来的话,不会直接fallback,并且会尝试请求命令,若是依然失败就将断路器继续设置为“打开”的状态,若是成功断路器就设置为“关闭”状态。
5.判断线程池/队列/信号量是否跑满,若是跑满进入降级步骤8,不然继续后续步骤.
、
若是在请求时,hystrix的线程池和请求队列,或者是信号量(不使用线程池的时候)已经被占满的状况下,Hystrix 也不会执行命令而是转接到fallback处理。
hystrix指的线程池不是容器的线程池,而是每一个依赖服务的专有线程池,这样作主要是为了当某个依赖服务有问题时,不会影响其余依赖服务,这种模式叫“舱壁模式”。这种模式就和Docker实现进程隔离的模式相同,Docker使得容器和容器直接不会相互影响,而Hystrix则使用该模式实现线程池的隔离。
hystrix线程池隔离的优点:
1:应用自身获得彻底保护,不会受不可控的依赖服务影响,即使给依赖服务分配的线程池填满,也不会影响应用自身的其余部分。
2:能够有效下降接入新服务的风险,当新服务接入时不稳定或存在问题时,不会影响应用其余请求、
3:当依赖服务从失效中恢复正常,它的线程池会被清理而且可以立刻恢复健康的服务,比容器级别的清理恢复要快不少。
4:线程池提供内置的并发实现,能够利用它为同步的依赖服务构建异步访问。
示例:
@HystrixCommand(fallbackMethod = "helloFallBack", commandKey = "helloService", groupKey = "Hello", threadPoolKey = "helloServiceIdThread", threadPoolProperties= {@HystrixProperty(name="coreSize",value="20"), @HystrixProperty(name="maxQueueSize",value="10")})
参数说明:coreSize 用来控制核心线程数,也就是最大并发量 默认为10
maxQueueSize 用来控制队列大小,当设置为-1时,线程池将使用SynchronousQueue实现的队列,不然将使用LinkedBlockingQueue实现的队列,默认为-1。
queueSizeRejectionThreshold 该参数用来设置队列的拒绝阀值,即便队列没有达到设置的最大值也能拒绝请求,该参数主要是对LinkedBlockingQueue的补充,由于LinkedBlockingQueue运行时不能动态修改它的大小,而经过该属性就能够调整拒绝请求的队列大小了,默认5。maxQueueSize为-1时无效,由于maxQueueSize为-1时,用的是SynchronousQueue,
timeInMilliseconds 该参数用来设置滚动时间窗的长度,单位为毫秒。该滚动时间窗的长度用于线程池的指标度量,它会被分红多个桶进行统计。默认10000
numBuckets 该参数用来设置滚动时间窗被划为成“桶”的数量,默认10
6.调用HystrixCommand的run方法.运行依赖逻辑 依赖逻辑调用超时,进入步骤8.
配置参数:
execution配置控制的是HystrixCommand.run()的执行
execution.isolation.strategy: 该属性用来设置执行的隔离策略。 1:Thread 线程 2:Semaphore 信号量 ,默认Thread
execution.isolation.thread.timeoutInMilliseconds:该属性用来配置HystrixCommand执行的超时间,若是超时直接进入fallBack,并将命令标记为TIMEOUT 默认值1000毫秒
execution.timeOut.enabled:该属性用来配置是否启用超时设置,当设置为false时execution.isolation.thread.timeoutInMilliseconds将不起做用。默认为true
execution.isolation.thread.interruptOntimeout:该属性用来配置当HstrixCommand.run()执行超时是否要将它中断
execution.isolation.thread.interruptOnCancel:该属性用来配置当HystrixCommand.run()执行被取消时是否要将它中断
execution.isolation.semaphore.maxConcurrentRequests:当HystrixCommand的隔离策略使用信号量时,用来设置信号量的大小(并发请求数)。当最大的并发数到达阀值时,后续的请求都会被拒绝,默认值10
7.判断逻辑是否调用成功。返回成功调用结果;调用出错,进入步骤8fallback.
判断调用成功主要就是看是否超时,是否抛出异常,这里要说的时若是设置了忽略异常,当异常类型是ClassCastException时 是不会触发fallback的,会将异常信息包装在HystrixBadRequestException中抛出。
@HystrixCommand(fallbackMethod = "helloFallBack", ignoreExceptions = ClassCastException.class)
8.计算熔断器状态,全部的运行状态(成功, 失败, 拒绝,超时)上报给熔断器,用于统计从而判断熔断器状态.
9.getFallback()降级逻辑。如下四种状况将触发getFallback调用:
没有实现getFallback的Command将直接抛出异常,fallback降级逻辑调用成功直接返回,降级逻辑调用失败抛出异常.
10.返回执行成功结果
Name |
Description |
Triggers Fallback? |
---|---|---|
执行失败 | 抛出异常 | YES |
超时 | 开始执行,但没有在容许的时间内完成 | YES |
断路器 | 断路器打开状态下 | YES |
线程池拒绝 | 线程池的容量满了或大于拒绝阀值 | YES |
信号量拒绝 | 信号量容量满了 | YES |
任务执行失败,执行超时,依赖熔断,执行线程池满,信号量满会fullback
熔断器实现三种类型的状态:open、half-open以及closed:
熔断执行流程:
当熔断器开关打开时, 请求被禁止经过.
熔断器开关处于打开状态, 通过一段时间后, 熔断器会自动进入半开状态, 这时熔断器只容许一个请求经过. 当该请求调用成功时, 熔断器恢复;失败,将继续保持熔断状态
自动熔断机制