Hystrix处理流程分析

通过Netflix Hystrix官方公布的流程图,我们来了解一下Hystrix的工作流程

官网流程图.png

1. 创建HystrixCommand对象或者HystrixObservableCommand对象

首先, 创建一个HystrixCommand对象或者HystrixObservableCommand对象用来表示对依赖服务的操作请求, 同时传递所有需要的参数, 它采用了命令模式来实现对服务调用操作的封装, 这两个Command对象分别针对不同的应用场景.

  • HystrixCommand: 依赖服务每次返回单一的回应。
HystrixCommand command = new HystrixCommand(arg1, arg2);
  • HystrixObservableCommand: 若期望依赖服务返回一个 Observable, 并应用Observer模式监听依赖服务的回应, 用在依赖的服务返回多个操作结果的时候.
HystrixObservableCommand command = new HystrixObservableCommand(arg1, arg2);
1.1 命令模式

将请求封装成对象, 使用不同的请求,队列或者日志请求来参数化其他对象, 就是命令模式. 命令模式也可以支持撤销操作. 当需要将请求的对象和执行请求的对象解耦的时候, 可以考虑使用命令模式.

1.2 命令模式的要点
  1. 命令模式将发出请求的对象和执行请求的对象解耦;
  2. 在被解耦的两者之间是通过命令对象进行沟通的, 命令对象封装了接收者和一个或一组动作;
  3. 调用者通过调用命令对象的execute()方法发出请求, 这会使得接收者的动作被调用;
  4. 调用者可以接受命令当作参数, 甚至在运行时动态地进行;
  5. 命令可以支持撤销, 做法是实现一个undo()方法来回到execute()方法被执行前的状态;

2. 调用Command的执行方法

执行Command就可以发起一次对依赖服务的调用.
要执行Command, 需要在4个方法中选择其中一个, 但主要是使用仅对HystrixCommand适用的两个:

  • execute(): 同步执行, 从依赖的服务返回一个单一的结果对象, 或者是在发生错误的时候抛出异常.
  • queue(): 异步执行, 直接返回一个Future对象, 其中包含了服务执行结束时要返回的单一结果对象.
  R value = command.execute();
  Future<R> fValue = command.queue();

而另外两种执行方式, 适用于HystrixObservableCommand:

  • observe(): 订阅一个Observable对象, Observable代表的是依赖服务返回的结果, 获取到一个那个代表结果的Observable对象的拷贝对象, 是一个 hot observable;
  • toObservable(): 返回一个Observable对象, 如果我们订阅这个对象, 就会执行command并且获取返回结果, 是一个 cold observable
  Observable<R> ohValue = command.observe();          //hot observable
  Observable<R> ocValue = command.toObservable();     //cold observable

execute()实际上会调用queue().get().queue(), 接着会调用toObservable().toBlocking().toFuture(), 也就是说, 无论是哪种执行command的方式, 最终都是依赖toObservable()去执行的.

3. 检查是否开启缓存

若当前命令的请求缓存功能(request cache)是被启用的, 并且该命令缓存命中, 那么缓存的结果会立即以Observable对象的形式返回.

4. 检查是否开启了短路器

在命令结果没有被缓存命中的时候, Hystrix会在执行命令前检查断路器是否为打开状态:

  • 如果断路器是打开的, 那么Hystrix不会执行命令, 而是转接到fallback处理逻辑(第8步).
  • 如果断路器是关闭的, Hystrix会检查是否有可用资源来执行命令(第5步).

5. 检查线程池/队列/semaphore是否已经满了

如果command对应的线程池, 列队, semeaphore已经满了, 那么也不会执行command, 而是直接调用fallback降级机制.

6. 执行command

Hystrix会根据我们编写的方法来决定采取什么样的方式去请求依赖服务.

  • HystrixCommand.run()--返回单个响应或抛出异常.
  • HystrixObservableCommand.construct()--返回Observable对象来发射多个结果, 或通过onError发送错误通知.

如果HystrixCommand.run()HystrixObservableCommand.construct()的执行, 超过了timeout时长的话, 那么command所在的线程就会抛出一个TimeoutException.
如果timeout了, 也会去执行fallback降级机制, 而且就不会管run()construct()返回的值了.
如果没有timeout的话, 那么就会拿到一些调用依赖服务获取到的结果, 然后hystrix会做一些logging记录和metric统计.

7. 短路健康检查

Hystrix会将每一个依赖服务的调用成功, 失败, 拒绝, 超时等事件, 都会发送给circuit breaker断路器.
短路器就会对调用成功/失败/拒绝/超时等事件的次数进行统计.
短路器会根据这些统计次数来决定, 是否要进行短路, 如果打开了短路器, 那么在一段时间内就会直接短路, 然后如果在之后第一次检查发现调用成功了, 就关闭断路器.

8. fallback处理

当命令执行失败时, Hystrix会进入fallback尝试回退处理, 也叫服务降级, 可以引入服务降级的请求有下面几种:

  • run()construct()抛出一个异常
  • 短路器打开
  • 线程池/队列/semaphore满了
  • command执行超时了

一般在降级机制中, 都建议给出一些默认的返回值, 比如静态的一些代码逻辑, 或者从内存中的缓存中提取一些数据, 尽量在这里不要再进行网络请求了.
即使在降级中, 一定要进行网络调用, 也应该将那个调用放在一个HystrixCommand中,进行隔离.

  • HystrixCommand中,上线getFallback()方法, 可以提供降级机制.
  • HystirxObservableCommand中, 实现一个resumeWithFallback()方法, 返回一个Observable对象, 可以提供降级结果.

如果fallback返回了结果,那么hystrix就会返回这个结果.

  • 对于HystrixCommand, 会返回一个Observable对象, 其中会发返回对应的结果;
  • 对于HystrixObservableCommand, 会返回一个原始的Observable对象.

如果没有实现fallback,或者是fallback抛出了异常, Hystrix会返回一个Observable, 但是不会返回任何数据.

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

  1. execute()——抛出异常
  2. queue()——成功时返回java.util.concurrent.Future, 但如果调用 Future.get()将抛出异常
  3. observe()——返回 Observable 对象, 当你订阅该 Observable 时, 将会立即终止并且调用订阅者的onError方法.
  4. toObservable()——同observe()

9. 返回成功的响应

Hystrix命令执行成功后, 会将处理结果直接返回或是以Observable的形式返回, 具体怎么返回要根据执行命令的方式来区分, 下图是四种执行方式的依赖关系:

  1. execute(), 获取一个Future.get(), 然后拿到单个结果;
  2. queue(), 返回一个Future;
  3. observer(), 立即订阅Observable, 然后启动8大执行步骤, 返回一个拷贝的Observable, 订阅时理解回调给你结果;
  4. toObservable(), 返回一个原始的Observable, 必须手动订阅才会去执行8大步骤.

参考文章:
1 https://www.jianshu.com/p/cd0d7ac31596
2 https://www.cnblogs.com/holly8/p/11226177.html
3 https://my.oschina.net/u/4006148/blog/3176044

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