• Spring Cloud学习 之 Spring Cloud Hystrix(断路器原理)


    断路器定义:

    public interface HystrixCircuitBreaker {
    	
        // 每个Hystrix都通过它判断是否被执行
        public boolean allowRequest();
    	
        // 返回当前断路器是否打开
        public boolean isOpen();
    	
        // 用来闭合断路器
    	void markSuccess();
    	
        public static class Factory {
    		// 维护了一个Hystrix命令与HystrixCircuitBreaker的关系
            // String类型的key通过HystrixCommandKey定义
            private static ConcurrentHashMap<String, HystrixCircuitBreaker> circuitBreakersByCommand = new ConcurrentHashMap<String, HystrixCircuitBreaker>();
    
    
            public static HystrixCircuitBreaker getInstance(HystrixCommandKey key, HystrixCommandGroupKey group, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
                HystrixCircuitBreaker previouslyCached = circuitBreakersByCommand.get(key.name());
                if (previouslyCached != null) {
                    return previouslyCached;
                }
    
                HystrixCircuitBreaker cbForCommand = circuitBreakersByCommand.putIfAbsent(key.name(), new HystrixCircuitBreakerImpl(key, group, properties, metrics));
                if (cbForCommand == null) {
    
                    return circuitBreakersByCommand.get(key.name());
                } else {
    
                    return cbForCommand;
                }
            }
            
            public static HystrixCircuitBreaker getInstance(HystrixCommandKey key) {
                return circuitBreakersByCommand.get(key.name());
            }
    
    static void reset() {
                circuitBreakersByCommand.clear();
            }
        }
    
    static class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {
        // 断路器对应的HystrixCommand实例的属性对象
            private final HystrixCommandProperties properties;
        // 用来让HystrixCommand记录各类度量指标的对象
            private final HystrixCommand记录各类度量指标的对象Metrics metrics;
    	// 断路器是否打开的标志,默认未false
            private AtomicBoolean circuitOpen = new AtomicBoolean(false);
    	// 断路器上次打开的时间戳
    		private AtomicLong circuitOpenedOrLastTestedTime = new AtomicLong();
            protected HystrixCircuitBreakerImpl(HystrixCommandKey key, HystrixCommandGroupKey commandGroup, HystrixCommandProperties properties, HystrixCommandMetrics metrics) {
                this.properties = properties;
                this.metrics = metrics;
            }
    		// 在半开路的情况下使用,若Hystrix命令调用成功,通过调用它将打开的断路器关闭
        	// 并重置度量指标 
            public void markSuccess() {
                if (circuitOpen.get()) {
                    if (circuitOpen.compareAndSet(true, false)) {
                      
                        metrics.resetStream();
                    }
                }
            }
    // 判断请求是否被允许,先根据配置对象中断路器
            @Override
            public boolean allowRequest() {
                if (properties.circuitBreakerForceOpen().get()) {
                  // 配置了强制打开,直接返回false
                    return false;
                }
                if (properties.circuitBreakerForceClosed().get()) {
                    // 配置了强制关闭,会允许所有请求,但同时也会调用isOpen()来执行断路器的计算逻辑
                    isOpen();
                  
                    return true;
                }
                // 默认情况下,会用过!isOpen() || allowSingleTest(),来判断请求是否被允许
                // 也就是说,断路器闭合,或者断路器关闭,但是allowSingleTest()为true
                return !isOpen() || allowSingleTest();
            }
    
            public boolean allowSingleTest() {
                long timeCircuitOpenedOrWasLastTested = circuitOpenedOrLastTestedTime.get();
     			// 断路器打开的情况下,每隔一段事件允许请求一次,默认为5s
                // 此时断路器处于一个半开路的状态下
                if (circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + properties.circuitBreakerSleepWindowInMilliseconds().get()) {
    
                    if (circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis())) {
    
                        return true;
                    }
                }
                return false;
            }
    	 // 判断当前断路器是否打开
            @Override
            public boolean isOpen() {
                if (circuitOpen.get()) {
    				// 如果断路器打开的标志为true就直接返回true,,表示断路器在打开状态
                    return true;
                }
    			// 否则从度量指标对象中获取HealthCounts统计对象做进一步判断(该对象记录了一个滚动事件窗内			   的请求信息快照,默认时间窗为10秒)
                HealthCounts health = metrics.getHealthCounts();
    
                if (health.getTotalRequests() < 
                    //如果他的QPS在预设的阈值范围内就返回false,表示断路器处于闭合状态。
                    //该值的默认值为20
                    properties.circuitBreakerRequestVolumeThreshold().get()) {
    
                    return false;
                }
    
                if (health.getErrorPercentage() < 
                    // 错误百分比在阈值内就返回false,该阈值默认为50%
                    properties.circuitBreakerErrorThresholdPercentage().get()) {
                    return false;
                } else {
                    // 如果上面两个参数都不满足,就打开断路器
                    if (circuitOpen.compareAndSet(false, true)) {
                        circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
                        return true;
                    } else {
                       
                        return true;
                    }
                }
            }
    
        }
    // 定义了一个什么都不做的断路器
     static class NoOpCircuitBreaker implements HystrixCircuitBreaker {
    
            @Override
            public boolean allowRequest() {
                return true;
            }
    
            @Override
            public boolean isOpen() {
                return false;
            }
    
            @Override
            public void markSuccess() {
    
            }
    
        }
    
    }
    
  • 相关阅读:
    前端性能优化(css动画篇)
    常用的布局及技巧
    一些有用的技能点
    做webApp遇到的一些坑及解决方案
    mysql5.7.30 编译安装
    windows使用Pandoc将Markdown转换为PDF文件
    源码编译安装keepalived
    源码编译php
    源码编译nginx
    源码编译PHP提示zip错误
  • 原文地址:https://www.cnblogs.com/daimzh/p/12854435.html
Copyright © 2020-2023  润新知