zoukankan      html  css  js  c++  java
  • Spring Cloud(4):断路器(Hystrix)

    Hystrix介绍

    相对于单一系统,分布式系统更容易遇到故障,所以我们一般通过构建冗余,使用集群和负载均衡来保证系统的弹性和高可用。当然,这种方式只解决了一部分问题,当服务崩溃时,我们很容易检测到,因此可以分流到集群中其他的服务中。但是,如果整个服务集群运行缓慢,不仅难以检测原因,而且还会触发连锁效应,从而影响整个应用程序生态系统,如果没有保护措施,一个性能不佳的服务可以迅速拖跨整个应用程序。原因如下:

    (1)服务的降级一般以某个问题开始,最终突然爆发,并形成不可逆转的势头。

    (2)对于远程调用该服务的客户端服务,这个调用一般是同步的,并且会一直等待(如果没有设定超时)

    (3)客户端服务遇到这种调用,通常设计为系统异常,而不是部分降级。

    我们可以使用Netflix的Hystrix实现客户端弹性模式,当服务崩溃时我们可以让客户端快速失败,免于崩溃,从而不继续占用如数据库连接,线程池之类的宝贵资源,并且防止故障向上游的级联传播(stop cascading failure)。一般有4种客户端弹性模式:

    (1)客户端负载均衡(client load balance)模式 - 在Spring Cloud中,Netflix Eureka及Ribbon实现了负载均衡,在服务发现(Eureka)一章中已经讲过,不再赘述

    (2)断路器(circuit breaker)模式 - Netflix Hystrix

    (3)后备(fallback)模式 - Netflix Hystrix

    (4)舱壁(bulkhead)模式 - Netflix Hystrix

     

    Hystrix策略

    断路器(circuit breaker)模式

    Hystrix默认的服务调用超时时间是是1s(execution.isolation.thread.timeoutInMilliseconds, default = 1000),当Hystrix遇到服务错误时,它将开始一个10s的窗口(计时器)(metrics.rollingStats.timeInMilliseconds, default = 10000),用于检查服务调用次数和故障百分比, 如果窗口期间没有达到最小调用次数20次(circuitBreaker.requestVolumeThreshold, default = 20),那么即使有几个(甚至全部)调用失败,Hystrix也不会采取行动(the circuit will not trip)。如果窗口期间达到最小调用次数20次,则要看故障百分比(circuitBreaker.errorThresholdPercentage, default = 50),如果故障百分比未超过50%,且10s的窗口已经过去,则Hystrix将重置断路器的统计信息,进入下一个10s,如果百分比超过50%的阈值,Hystrix将触发断路器,使将来几乎所有调用都失败(会让部分调用来进行测试,以检查服务是否恢复)。如果触发断路器,断路器跳闸后,将进入一个新的的5s窗口(circuitBreaker.sleepWindowInMilliseconds, default = 5000),即每隔5s调用一次这个“坏”服务,如果失败则HHystrix继续保持断开,并进入下一个5s的尝试。如果成功,则Hystrix将重置断路器的统计信息并恢复调用。

    隔离策略(execution.isolation.strategy, default = THREAD):分为THREAD和SEMAPHORE。THREAD指在单独的线程上执行,并发请求受线程池中的线程数限制。SEMAPHORE指在调用线程上执行,并发请求量受信号量计数限制。在默认情况下,推荐HystrixCommands使用THREAD隔离策略,HystrixObservableCommand使用SEMAPHORE隔离策略。只有在高并发(单个实例每秒达到几百个调用)的调用时,才需要修改HystrixCommands的隔离策略为SEMAPHORE。

    滑动窗口及桶(bucket)(metrics.rollingStats.numBuckets, default = 10):Hystrix的统计器是由滑动窗口(10s)来实现的,bucket是Hystrix统计滑动窗口数据时的最小单位。默认是10,即每滑过窗口的1/10就统计一次数据。

    后备(fallback)模式

    fallbackMethod属性在当前类中定义了一个方法,如果Hystrix执行失败,就执行该方法

    舱壁(bulkhead)模式

    在不使用舱壁模式的情况下,Hystrix默认共享同一个线程池来对各个服务执行调用的,而这些服务调用可能是各不相同,比如REST服务,数据库调用等。当某个服务存在大量请求时,Hystrix线程池中的线程可能会被耗尽,因为一个服务会占据默认线程池中的所有线程。而舱壁模式则是为一个微服务中不同的调用创建舱壁,即单独的线程池,池互不影响。我们使用threadPoolKey来定义一个线程池的名字,使用threadPoolProperties来配置属性,其中,coreSize定义线程池中线程的最大数量,maxQueueSize定义排队进入线程池的队列的大小。

    [注] 上面标颜色的参数会在下面有具体的使用方式。

    使用Hystrix

    首先,在一个客户端服务中,在pom.xml中添加依赖spring-cloud-starter-netflix-hystrix。

    <!-- Spring cloud starter: netflix-hystrix -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

     其次,在启动类Application中加入@EnableCircuitBreaker注解。

    @SpringBootApplication
    @EnableCircuitBreaker
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }

    上面3种模式可以如下配置:

        @Autowired
        private LoadBalancerClient loadBalancer;
    
        @Autowired
        private OAuth2RestTemplate restTemplate;
    
        //@formatter:off
        @HystrixCommand(
            commandProperties = {
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"),
                @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
                @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
                @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
                @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000"),
                @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10")
            }, // 断路器模式
            fallbackMethod = "callFallbackMethod1", // 后备模式
            threadPoolKey = "findAllPoolKey",
            threadPoolProperties = {
                @HystrixProperty(name = "coreSize", value = "10"),
                @HystrixProperty(name = "maxQueueSize", value = "-1")
            } // 舱壁模式
        )
        //@formatter:on
        public String getSqlInfo(String env, String db, String name) {
    
            ServiceInstance instance = loadBalancer.choose("app-db");
            String path = String.format("http://%s:%s/app-db/structure-search/app/MORT/env/%s/db/%s/name/%s",
                    instance.getHost(), instance.getPort(), env, db, name);
            logger.info(path);
    
            ResponseEntity<String> response = restTemplate.exchange(path, HttpMethod.GET, null, String.class);
            String body = response.getBody();
            logger.info("The Response body is: " + body);
    
            return body;
        }
    
        private String callFallbackMethod1(String env, String db, String name) {
            return "Result is NULL";
        }

    我们也可以在类级别和整个应用程序级别设置这些参数。

    在类级别是这样设置的:

    @DefaultProperties(commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") })
    public class CallService {
    }

    在production环境中,我们有时候会需要调整Hystrix数据,这种情况下推荐将配置外部化到Spring Cloud Config中,这样就无须再修改代码,编译和部署:

    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
  • 相关阅读:
    英国下院通过法案允许合成人兽胚胎
    老外关于思考时间的问与答
    性能测试中用LambdaProbe监控Tomcat
    BT下载原理
    汽车维修行业呼吁大学生加入修车行列
    一个女研究生(高级测试工程师)的职业选择
    微软称20日验证Windows与Office 盗版将黑屏 网友评论
    Xbox摇身变NAS:BT的使用问题与性能测试
    李开复建言大学生:求职中不要把钱看得太重
    IBM雇员将罢工15分钟 为抗议公司裁员
  • 原文地址:https://www.cnblogs.com/storml/p/11214626.html
Copyright © 2011-2022 走看看