资讯专栏INFORMATION COLUMN

Netflix Hystrix断路器原理分析

Lemon_95 / 2987人阅读

摘要:断路器原理断路器在和执行过程中起到至关重要的作用。其中通过来定义,每一个命令都需要有一个来标识,同时根据这个可以找到对应的断路器实例。一个啥都不做的断路器,它允许所有请求通过,并且断路器始终处于闭合状态断路器的另一个实现类。

断路器原理

断路器在HystrixCommand和HystrixObservableCommand执行过程中起到至关重要的作用。查看一下核心组件HystrixCircuitBreaker

package com.netflix.hystrix;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

import com.netflix.hystrix.HystrixCommandMetrics.HealthCounts;
import rx.Subscriber;
import rx.Subscription;

public interface HystrixCircuitBreaker {

    boolean allowRequest();
    
    boolean isOpen();

    void markSuccess();

    void markNonSuccess();

    boolean attemptExecution();

    class Factory {
        // String is HystrixCommandKey.name() (we can"t use HystrixCommandKey directly as we can"t guarantee it implements hashcode/equals correctly)
        private static ConcurrentHashMap circuitBreakersByCommand = new ConcurrentHashMap();
    }


    class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {
    }

    static class NoOpCircuitBreaker implements HystrixCircuitBreaker {
    }

}

下面先看一下该接口的抽象方法:

allowRequest(): 每个Hystrix命令的请求都通过它判断是否被执行(已经不再使用,使用attemptExecution()方法进行判断)

attemptExecution(): 每个Hystrix命令的请求都通过它判断是否被执行

isOpen(): 返回当前断路器是否打开

markSuccess(): 用来关闭断路器

markNonSuccess: 用来打开断路器

下面看一下该接口中的类:

Factory: 维护了一个Hystrix命令和HystrixCircuitBreaker的关系的集合ConcurrentHashMap circuitBreakersByCommand。其中key通过HystrixCommandKey来定义,每一个Hystrix命令都需要有一个Key来标识,同时根据这个Key可以找到对应的断路器实例。

NoOpCircuitBreaker: 一个啥都不做的断路器,它允许所有请求通过,并且断路器始终处于闭合状态

HystrixCircuitBreakerImpl:断路器的另一个实现类。

HystrixCircuitBreakerImpl介绍

在该类中定义了断路器的五个核心对象:

HystrixCommandProperties properties:断路器对应实例的属性集合对象

HystrixCommandMetrics metrics:用来让HystrixCommand记录各类度量指标的对象

AtomicReference status: 用来记录断路器的状态,默认是关闭状态

AtomicLong circuitOpened:断路器打开的时间戳,默认-1,表示断路器未打开

AtomicReference activeSubscription: 记录HystrixCommand

isOpen方法介绍
        @Override
        public boolean isOpen() {
            if (properties.circuitBreakerForceOpen().get()) {
                return true;
            }
            if (properties.circuitBreakerForceClosed().get()) {
                return false;
            }
            return circuitOpened.get() >= 0;
        }

用来判断断路器是否打开或关闭。主要步骤有:

如果断路器强制打开,返回true

如果断路器强制关闭,返回false

判断circuitOpened的值,如果大于等于0,返回true, 否则返回false

attemptExecution方法介绍
        private boolean isAfterSleepWindow() {
            final long circuitOpenTime = circuitOpened.get();
            final long currentTime = System.currentTimeMillis();
            final long sleepWindowTime = properties.circuitBreakerSleepWindowInMilliseconds().get();
            return currentTime > circuitOpenTime + sleepWindowTime;
        }

        @Override
        public boolean attemptExecution() {
            if (properties.circuitBreakerForceOpen().get()) {
                return false;
            }
            if (properties.circuitBreakerForceClosed().get()) {
                return true;
            }
            if (circuitOpened.get() == -1) {
                return true;
            } else {
                if (isAfterSleepWindow()) {
                    if (status.compareAndSet(Status.OPEN, Status.HALF_OPEN)) {
                        //only the first request after sleep window should execute
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            }
        }

该方法的主要逻辑有以下几步:

如果断路器强制打开,返回false,不允许放过请求

如果断路器强制关闭,返回true,允许放过请求

如果断路器是关闭状态,返回true,允许放过请求

判断当前时间是否超过断路器打开的时间加上滑动窗口的时间,如果没有超过,返回false,不允许放过请求

如果没有超过,如果断路器是打开状态,并且设置断路器状态为半开状态成功时,返回true,允许放过请求

如果失败,则返回false,不允许放过请求

markSuccess方法
        @Override
        public void markSuccess() {
            if (status.compareAndSet(Status.HALF_OPEN, Status.CLOSED)) {
                //This thread wins the race to close the circuit - it resets the stream to start it over from 0
                metrics.resetStream();
                Subscription previousSubscription = activeSubscription.get();
                if (previousSubscription != null) {
                    previousSubscription.unsubscribe();
                }
                Subscription newSubscription = subscribeToStream();
                activeSubscription.set(newSubscription);
                circuitOpened.set(-1L);
            }
        }

该方法主要用来关闭断路器,主要逻辑有以下几步:

如果断路器状态是半开并且成功设置为关闭状态时,执行以下步骤。

重置度量指标对象

取消之前的订阅,发起新的订阅

设置断路器的打开时间为-1

代码地址

spring-cloud-example

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76951.html

相关文章

  • Spring Cloud Hystrix入门和Hystrix命令原理分析

    摘要:系统需要支持命令的撤销。第步计算断路器的健康度会将成功失败拒绝超时等信息报告给断路器,断路器会维护一组计数器来统计这些数据。第步,当前命令的线程池请求队列或者信号量被占满的时候。 断路由器模式 在分布式架构中,当某个服务单元发生故障之后,通过断路由器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障...

    Betta 评论0 收藏0
  • SpringCloud(第 014 篇)电影 Ribbon 微服务集成 Hystrix 路器实现失

    摘要:当服务宕机或者不可用时,即请求超时后会调用此方法。添加电影微服务启动类电影微服务集成断路器实现失败快速响应,达到熔断效果。 SpringCloud(第 014 篇)电影 Ribbon 微服务集成 Hystrix 断路器实现失败快速响应,达到熔断效果 - 一、大致介绍 1、Hystrix 断路器的原理很简单,如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,...

    StonePanda 评论0 收藏0
  • SpringCloud之Hystrix

    摘要:如果由包装的工作不尊重,那么线程池中的线程将继续它的工作,尽管客户机已经收到了。这种行为可能会使线程池饱和,尽管负载正确释放。 showImg(https://segmentfault.com/img/remote/1460000018779851); 简介 在分布式环境中,许多服务依赖关系中的一些必然会失败。Hystrix是一个库,它通过添加延迟容忍和容错逻辑来帮助您控制这些分布式服...

    RancherLabs 评论0 收藏0
  • springCloud学习3(Netflix Hystrix弹性客户端)

    摘要:在舱壁模式中可以隔离每个远程资源,并分配各自的线程池,使之互不影响。 springcloud 总集:https://www.tapme.top/blog/detail/2019-02-28-11-33 本次用到全部代码见文章最下方。 一、为什么要有客户端弹性模式   所有的系统都会遇到故障,分布式系统单点故障概率更高。如何构建应用程序来应对故障,是每个软件开发人员工作的关键部分。但是通...

    yagami 评论0 收藏0
  • 11、RestTemplate+Ribbon整合路器Hystrix

    摘要:为了保证服务高可用性,单个服务通常会进行集群部署。这时断路器就派上用场了。当对某个服务的调用的不可用达到一个阀值默认是秒次断路器将会被自动被打开。断路打开后,方法可以直接返回一个预先设置的固定值。 公众号: java乐园 在微服务架构中,根据业务需求拆分成一个个的微小服务,然后服务与服务之间可以相互RPC远程调用。在Spring Cloud可以使用RestTemplate+Ribbo...

    elva 评论0 收藏0

发表评论

0条评论

Lemon_95

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<