hystrix


如何设计一个高可用的系统?

  1. 限流:高并发的流量涌入进来, 比如说突然间一秒钟100万的QPS 废掉了。 10万的qps进入系统,其他90万的qps被拒绝了。
  2. 熔断:系统后端的一些依赖,出来一些故障,比如说mysql挂掉了,每次的请求都是报错的, 熔断了, 后续的请求过来直接不接收了,拒绝访问,10分钟后再次尝试恢复没有
  3. 降级:mysql挂了, 系统发现了, 自动降级, 从内存里存的少量的数据中, 去提取一些数据出来,
  4. 运维监控: 监控+ 报警+优化, 各种异常的情况,有问题就及时报警,优化一些系统配置和参数,后者代码、


hystrix 的设计原则是什么?

  1. 对依赖服务调用时出现的延时和失败进行控制和容错保护
  2. 在复杂的分布式系统中,阻止某一个依赖服务的故障在整个系统中蔓延
  3. 提供了fail-fast(快速失败) 和快速恢复的支持
  4. 提供fallback 优雅降级的支持
  5. 支持近实时的监控,报警以及运维操作

hystrix 的更加细节的设计原则是什么?


阻止任何一个依赖服务耗尽所有的资源,比如tomcat中的所有线程资源

避免请求排队和积压,采用的限流的fail fast来控制故障

提供fallback降级机制来应对故障

使用资源隔离技术比如bulkhead (舱壁隔离技术) swimlane(泳道技术) circuit breaker(短路技术) 来限制任何一个依赖服务的故障的影响

通过近实时的统计/监控/报警功能,来提高故障发现的速度

通过近实时的属性和配置热修改功能,来提高故障处理和恢复的速度

保护依赖服务调用的所有故障情况,而不仅仅只是网络故障情况

调用这个依赖服务的时候, client调用包有bug 阻塞 等等, 依赖服务的各种各样的调用过的故障, 都可以处理,

hystrix 是如何实现它的目标的?

通过hystrixCommand 或者HystrixObservableCommand 来封装对外部依赖的访问请求, 这个访问请求一般运行在独立的线程中,资源隔离

对于超出我们设定的阈值的服务调用,直接进行超时,不允许其耗费过长时间阻塞住, 这个超时时间默认的是99.5% 的访问时间, 但是一般我们可以自己设置一下

为每一个依赖服务维护一个独立的线程池, 或者是semaphore,当线程池已满时,之拒绝对这个服务的调用,

如果对一个依赖的服务的调用失败次数超过一定的阈值,自动进行熔断,在一定时间内对该服务的调用直接降价,一段时间后在自动尝试恢复

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

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


将商品服务的接口调用的逻辑进行封装


hystrix 进行资源隔离,其实就是提供一个抽象的叫做command,如果你对某个依赖服务进行调用的所有请求, 都会被隔离到一份资源池内。

对这个依赖服务的所有调用请求, 全部走这个资源池内的资源, 不会去用其他资源了, 这个就叫资源隔离。

hystrix 最基本的资源隔离技术,线程池隔离技术。

对某一个依赖服务,商品服务, 所有的调用请求,全部隔离到一个线程池内, 对商品服务的每次调用请求都封装在一个command里面,每个command 都是使用线程池内的
一个线程去执行,现在同时发起的调用量已经到了1000了,但是线程池内就10个线程, 最多就只会有用着10个线程去执行。

对上坪服务的请求, 因为接口调用的延迟, 将tomcat内所有的线程资源全部都耗尽,不会出现了。

hystrixCommand:是用来获取一条数据的。

HystrixObservableCommand : 设计用来获取多条数据的

execute() 是同步调用

queue() 是异步调用


hystrix 最核心的功能,就是资源隔离,要解决最核心的问题,就是将多个依赖服务的调用分离隔离到各自自己的资源池内。


hystrix 两种技术:


线程池资源隔离 、 信号量隔离

这两种技术的区别:


线程池隔离:是在自己创建一个线程池在使用线程来访问资源来,  适合的场景( 适合绝大部分的场景,99%的,线程池对依赖服务的网络请求的调用和访问,和timeout这种问题)  

信号量隔离( semaphore ):是没有自己的线程,是通过请求的线程直接去访问要请求的资源。(适合,你访问的服务不依赖外部的访问,而是对内部的一些比较复杂的业务逻辑的访问,这种的访问像系统的内部代码。)

 选择的隔离策略:  execution.isolation.strategy 


command 线程池:


threadpool key 代表了一个hystrixThreadpool .用来进行统一监控,缓存, 统计, 默认的threadPool key 就是 command group 名称

每个command 都会跟它的threadPool key 对应的threadpool 绑定在一起, 如果不想直接用command group , 也可以手动设置 thread pool name

command treadpool -> command group -> command key

command key 代表了一个类command, 一般来说, 代表了底层的依赖服务的一个接口,

command group 代表了某一个底层的依赖服务, 合理,一个依赖服务可能会暴漏出来多个接口, 每个接口对应一个command key

command group 在逻辑上去, 组织起来一推command key 的调用, 统计信息,成功次数, timeout 超时的次数, 失败的次数 可以看到的某个服务整体的一些访问情况,

command group 一般来说, 推荐是根据一个服务去划分出一个线程池, command key默认都是术语同一个线程池的,

比如说你以一个服务为粒度, 估算出来这个服务的每秒的所有接口哦加起来的整体aps在100左右,你调用那个服务的当前服务,部署了10个服务实力,每个服务的实例上,其实用这个command group对应这个服务,给一个线程池, 量大概在10个左右, 就可以了, 你对整个服务的整体的访问aps 大概每秒100左右 ,一般来说command group 是用来在逻辑上组合一推command的,比如, 对于一个服务种的某个功能模块来说, 希望将这个功能模块内的所有command放在一个group种,那么在监控和报警的适合可以放一起看

command group 对应一个服务,但是这个服务暴漏出来的几个接口, 访问量很不一样, 差异非常大。 你可能就希望在这个服务command group 内部, 包含的对应多个接口 command key 做一些细粒度的资源隔离,


对同一个服务的不同接口, 都是用不同的线程池,

command key -> command group

command key -> 自己的threadpool key

逻辑上来说, 多个command key 属于一个command group 在统计的时候, 会放在一起统计 每个command key 有自己的线程池,每个接口有自己的线程池,去做资源隔离
和限流。 但是对于threadpool 资源隔离来说,可能是希望能够拆分的更加一致一些。比如在一个功能模块内,对不同的请求可以使用不同的threadpool

command group 一般来说,可以是对应一个服务,多个command key 对应这个服务的多个接口,多个接口的调用共享同一个线程池, 如果说你的command key 要用自己的
线程池。可以定义自己的threadpool key 就可以了。


调用 command 的执行方法

要执行command 需要在4种方法种选择其中的一个, execute(), queue() observe(), toObservable()

其中execute() 和 queue() 仅仅对hystrixcommand适用

execute() 调用后直接block住, 术语同步调用, 知道依赖通过调用服务返回单挑数据结果,或者是抛出异常。

queue() 返回一个future 属于异步调用,后面可以通过future获取单条数据

observe() 订阅一个observable对象,observable代表的是依赖服务返回结果,获取到一个那个代表结果observable对象的拷贝对象

toOservable() 返回一个observable对象,如果我们订阅这个对象,就会执行command并且获取返回结果。


短路器的工作原理:

1 如果经过短路器流量超过了一定的阈值, HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()

比如:要求在10s内, 经过短路器的流量必须达到20个, 可是在10s内,经过短路器的流量只有10个, 那么根本不会去判断要不要短路

2 如果短路器统计到的异常调用的占比超过了一定的阈值, hystrixCommandProperties.circuitBreakerErrorThresholdPercentage()

如果说达到了上面的要求, 比如说在10s内,经过短路器的流量, 达到了30个,同时其中的异常访问的数据,占到了一定的比例, 比如说60% 的请求都是异常,会开启短路。


3 然后短路器 从close 状态转换到open 状态

4 短路器打开的时候 ,所有经过该短路器的请求全部被短路, 不调用后端服务, 直接走fallback降级

5 经过一段时间之后, hystrixCommandProperties.circuitBreakerSlleepWindowInMilliseconds(), 会half-open 让一条请求经过短路器,看能不能正常调用,如果调用成功了, 那么就自动恢复,转到close状态。

这个时候短路器会自动恢复,half-open 半开状态

原文地址:https://www.cnblogs.com/yishuo/p/14668154.html