跳闸了啊! 服务容灾:熔断器简介

雪崩效应

现如今SOA、微服务风愈演愈烈,越来越多的业务和资源被以服务的形式包装和发布,服务间又可能会依赖其他各种服务。由此而来不可避免的会产生很多问题。

比如一个服务,其依赖了另外30个服务。假设每个服务的可用率都有三个9(99.9%),那么我们计算一下:

99.99%^30 = 99.7%

现实很残酷,这个服务的实际可用性只能是99.7%,也就是说每个月这个服务都要好宕机8000+秒~~~


image

正常用户请求时,服务内部依次请求A\P\H\I服务,兵返回响应结果。

image

非常不幸,我们的I服务出了某些问题,此时我们的用户请求就被堵塞在I服务处。

image

更加悲剧的是,后续越来越多的请求都被堵塞在I服务处,而这些被堵塞的请求会占用线程、IO、网络等系统资源,随着资源被占用的越来越多,本来不存在的性能问题也会随之而来,造成系统中的其他服务出现问题,甚至导致系统奔溃。

这也就是我们常说的雪崩效应


服务容灾

为了避免出现服务的雪崩,我们需要对服务做容灾处理。

常规的服务容灾处理思路有:

  • 资源隔离
  • 超时设定
  • 服务降级
  • 服务限流

其中每种思路又可以有不同的解决方案。

比如资源隔离可以通过将不同的服务发布在独立的docker容器或服务器中,这样即使一个服务出现问题,也不会殃及池鱼。

服务降级和服务限流可以通过前端nginx+lua来实现,当服务处理延迟或宕机时,nginx可以直接返回固定的降级/失败响应,已快速跳过问题服务。


Hystrix

Hystrix,是Netflix的一个开源熔断器,通过Hystrix,我们可以很方便的实现资源隔离、限流、超时设计、服务降级等服务容灾措施,并且还提供了强大的监控,可以查看各个熔断器的允许情况。

image

通过上图,可以看出,Hystrix提供了一个HystrixCommand用来包装调用请求。HystrixCommand的执行流程大概如下:
1.首先检查缓存中是否有结果。如果有则直接返回缓存结果。
2.判断断路器是否开启,如果断路器闭合,执行降级业务逻辑并返回降级结果。
3.判断信号量/线程池资源是否饱和,如饱和则执行降级业务逻辑并返回降级结果。
4.调用实际服务,如发生异常,执行降级业务逻辑并返回降级结果,并调整断路器阈值。
5.判断实际业务是否超时,超时则返回超时响应结果,并调整断路器阈值。

了解了流程,来看下如何使用Hystrix。首先我们需要定义一个命令类来包装我们的业务调用:

//继承HystrixCommand
public class CommandHelloFailure extends HystrixCommand<String> {

    private final String name;

    public CommandHelloFailure(String name) {
        //设置分组key,分组key可以用在报表、监控中,默认的线程池隔离也基于分组key
         super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
            //指定命令key,可
            .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
            //指定线程池key,取代默认的分组key
            .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
        /*
        //线程池隔离模式,不写默认是线程池隔离模式
        HystrixCommandProperties.Setter()
           .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)
        //信号量隔离模式
        HystrixCommandProperties.Setter()
           .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
        //超时时间,默认1秒
        HystrixCommandProperties.Setter()
           .withExecutionTimeoutInMilliseconds(int value)  
        //信号量模式下,最大并发请求限流,默认值10
        HystrixCommandProperties.Setter()
           .withFallbackIsolationSemaphoreMaxConcurrentRequests(int value)  
        //熔断器阈值,默认20
        HystrixCommandProperties.Setter()
            .withCircuitBreakerRequestVolumeThreshold(int value)
        //熔断器关闭时间,默认5秒
        HystrixCommandProperties.Setter()
            .withCircuitBreakerSleepWindowInMilliseconds(int value)
        */
        this.name = name;
    }

    @Override
    //执行实际服务,这里模拟全部返回异常
    protected String run() {
        throw new RuntimeException("this command always fails");
    }

    @Override
    //执行降级业务
    protected String getFallback() {
        return "Hello Failure " + name + "!";
    }

    @Override
    //从缓存中获取
    protected String getCacheKey() {
        ...
    }
} 

使用这个命令类也非常简单:

//同步执行
String s = new CommandHelloWorld("Bob").execute();
//异步执行
Future<String> s = new CommandHelloWorld("Bob").queue();
//响应式
Observable<String> s = new CommandHelloWorld("Bob").observe();

通过Hystrix提供的监控界面,我们可以观察到各个熔断器的执行情况:

image

更多说明和例子可以查看Hystrix的wiki


Hystrix和Spring boot

想在spring boot中使用Hystrix就更加简单了,只需要引入spring-cloud-starter-hystrix,

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

然后添加注解使用Hystrix
@EnableCircuitBreaker
@EnableHystrixDashboard

最后在需要使用熔断器的地方标记注解即可。

@HystrixCommand(groupKey = "xxx", fallbackMethod = "yyy")
public String doSomething() 

遥想2015年9月7日,上交所、深交所、中金所宣布,拟在保留现有个股涨跌幅制度前提下,引入指数熔断机制。随后A股联系两天下跌熔断,提前收盘。其中这里的熔断机制和我们今天讨论的熔断器思路一致,但是反而导致了A股暴跌,这也说明了我们还是得从根源产出高可用的服务,而不是依赖某些外部措施帮助我们提高可用性。同时说明了A股比咱写的垃圾服务更加不可靠,还是安心当个码农吧。

最后,就问各位童鞋,敢不敢点个赞~~~~

参考资料:
https://github.com/Netflix/Hystrix
http://www.cnblogs.com/jesse2013/p/things-architect-must-know.html

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

推荐阅读更多精彩内容