Java熔断框架有哪些_降级熔断框架 Hystrix 源码解析:滑动窗口统计

降级熔断框架 Hystrix 源码解析:滑动窗口统计

概述

Hystrix 是一个开源的降级熔断框架,用于提高服务可靠性,适用于依赖大量外部服务的业务系统。什么是降级熔断呢?

降级

业务降级,是指牺牲非核心的业务功能,保证核心功能的稳定运行。简单来说,要实现优雅的业务降级,需要将功能实现拆分到相对独立的不同代码单元,分优先级进行隔离。在后台通过开关控制,降级部分非主流程的业务功能,减轻系统依赖和性能损耗,从而提升集群的整体吞吐率。

降级的重点是:业务之间有优先级之分。降级的典型应用是:电商活动期间关闭非核心服务,保证核心买买买业务的正常运行。

熔断

老式电闸都安装了保险丝,一旦有人使用超大功率的设备,保险丝就会烧断以保护各个电器不被强电流给烧坏。同理我们的接口也需要安装上“保险丝”,以防止非预期的请求对系统压力过大而引起的系统瘫痪,当流量过大时,可以采取拒绝或者引流等机制。

同样在分布式系统中,当被调用的远程服务无法使用时,如果没有过载保护,就会导致请求的资源阻塞在远程服务器上耗尽资源。很多时候,刚开始可能只是出现了局部小规模的故障,然而由于种种原因,故障影响范围越来越大,最终导致全局性的后果。这种过载保护,就是熔断器。

在 hystrix 中,熔断相关的配置有以下几个:滑动窗口长度,单位毫秒

hystrix.command.HystrixCommandKey.circuitBreaker.sleepWindowInMilliseconds

滑动窗口滚动桶的长度,单位毫秒

hystrix.command.HystrixCommandKey.metrics.rollingPercentile.bucketSize

触发熔断的失败率阈值

hystrix.command.HystrixCommandKey.circuitBreaker.errorThresholdPercentage

触发熔断的请求量阈值

hystrix.command.HystrixCommandKey.circuitBreaker.requestVolumeThreshold

从配置信息里可以看出来,熔断逻辑判断里使用了滑动窗口来统计服务调用的成功、失败量。那么这里的滑动窗口是如何实现的呢?下面我们深入源码来研究一下。

注:使用的源码版本是 2017-09-13 GitHub 上 master 分支最新代码。

滑动窗口

在 hystrix 里,大量使用了 RxJava 这个响应式函数编程框架,滑动窗口的实现也是使用了 RxJava 框架。

源码分析

一个滑动窗口有两个关键要素组成:窗口时长、窗口滚动时间间隔。通常一个窗口会划分为若干个桶 bucket,每个桶的大小等于窗口滚动时间间隔。也就是说,滑动窗口统计数据时,分两步:统计一个 bucket 内的数据;

统计一个窗口,即若干个 bucket 的数据。

bucket 统计的代码位于 BucketedCounterStream 类中,其关键的代码如下所示:// 这里的代码并非全部,只展示了和 bucket 统计相关的关键代码public abstract class BucketedCounterStream {    protected final int numBuckets;    protected final Observable bucketedStream;    protected final AtomicReference subscription = new AtomicReference(null);    private final Func1, Observable> reduceBucketToSummary;    protected BucketedCounterStream(final HystrixEventStream inputEventStream, final int numBuckets, final int bucketSizeInMs,                                    final Func2 appendRawEventToBucket) {        this.numBuckets = numBuckets;        this.reduceBucketToSummary = new Func1, Observable>() {            @Override

public Observable call(Observable eventBucket) {                return eventBucket.reduce(getEmptyBucketSummary(), appendRawEventToBucket);

}

};        final List emptyEventCountsToStart = new ArrayList();        for (int i = 0; i 

emptyEventCountsToStart.add(getEmptyBucketSummary());

}        this.bucketedStream = Observable.defer(new Func0>() {            @Override

public Observable call() {                return inputEventStream

.observe()

.window(bucketSizeInMs, TimeUnit.MILLISECONDS) //bucket it by the counter window so we can emit to the next operator in time chunks, not on every OnNext

.flatMap(reduceBucketToSummary)                //for a given bucket, turn it into a long array containing counts of event types

.startWith(emptyEventCount

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值