zoukankan      html  css  js  c++  java
  • 服务熔断Hystrix入门

    1 服务容错的核心知识

    1.1 雪崩效应

    • 在微服务架构中,一个请求需要调用多个服务是非常常见的。如客户端访问A服务,而A服务需要调用B服务,B服务需要调用C服务,由于网络原因或者自身的原因,如果B服务或C服务不能及时响应,A服务将处于阻塞状态,直到B服务C服务响应。此时如果有大量的请求涌入,容器的线程资源会被消耗完毕,导致服务瘫痪。服务和服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。

    雪崩效应

    • 雪崩是系统中的蝴蝶效应,导致其发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方法响应变慢,亦或是某台机器的资源耗尽。从源头上我们无法完全杜绝雪崩源头的发生,但是雪崩的根本原因来源于服务之间的强依赖,所以我们可以提前评估,做好熔断隔离限流

    1.2 服务隔离

    • 顾名思义,它是指系统按照一定的原则划分若干个服务模块,各个模块之间相互独立,无强依赖性。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不涉及到其他模块,不影响整体的系统服务。

    1.3 熔断降级

    • 熔断,这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因为当问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫熔断。

    熔断降级

    • 所谓降级,就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。也可以理解为兜底。

    1.4 服务限流

    • 限流可以认为是服务降级的一种,限流就是限制系统的输入和输出流量来达到保护系统的目的。一般来说,系统的吞吐量是可以被测算的,为了保证系统的稳固运行,一旦到达需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。比如:推迟解决、拒绝解决或者是部分拒绝解决等等。

    2 Hystrix介绍

    • Hystrix是由Netflix公司开源的一个延迟和容错库,用于隔离访问远程系统、服务或第三方库,防止级联失败,从而提升系统的可用性和容错性。Hystrix主要通过以下的几点实现延迟和容错:
    • 1️⃣包裹请求:使用HystrixCommand包裹对依赖的调用逻辑,每个命令在独立线程中执行。使用了设计模式中的命令模式。
    • 2️⃣跳闸机制:当某服务的错误率超过一定的阈值时,Hystrix可以自动或者手动跳闸,停止请求该服务一段时间。
    • 3️⃣资源隔离:Hystrix为每个依赖度维护了一个小型的线程池(或者信号量)。如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。
    • 4️⃣监控:Hystrix可以近乎实时的监控运行指标和配置的变化,例如成功、失败、超时、被拒绝的请求等等。
    • 5️⃣回退机制:当请求失败、超时、被拒绝、或当断路器打开时,执行回退逻辑。回退逻辑由开发人员自行提供,例如返回一个缺省值。
    • 6️⃣自我修复:断路器打开一段时间后,会自动进入“半开”状态。

    3 Rest实现服务降级

    3.1 引入Hystrix的依赖

    • 修改部分:
    <!-- 引入Hystrix依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
    • 完整部分:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>spring_cloud_demo</artifactId>
            <groupId>org.sunxiaping</groupId>
            <version>1.0</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>order_service_hystrix_rest9006</artifactId>
    
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.retry</groupId>
                <artifactId>spring-retry</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!--   导入Eureka Client对应的坐标     -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <!-- 引入Hystrix依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
    
        </dependencies>
    
    </project>
    

    3.2 在启动类上激活Hystrix

    • Order9006Application.java
    package com.sunxiaping;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
    
    @SpringBootApplication
    @EnableCircuitBreaker //激活Hystrix
    public class Order9006Application {
        public static void main(String[] args) {
            SpringApplication.run(Order9006Application.class, args);
        }
    }
    

    3.3 配置熔断处理的降级逻辑

    • OrderController.java
    package com.sunxiaping.controller;
    
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.sunxiaping.domain.Product;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    @RequestMapping(value = "/order")
    public class OrderController {
        @Autowired
        private RestTemplate restTemplate;
    
    
        /**
         * 使用注解配置熔断保护
         * fallbackMethod:配置熔断之后的降级方法
         *
         * @param id
         * @return
         */
        @GetMapping(value = "/buy/{id}")
        @HystrixCommand(fallbackMethod = "orderFallBack")
        public Product buy(@PathVariable(value = "id") Long id) {
    
            Product product = restTemplate.getForObject("http://service-product/product/findById/" + id, Product.class);
    
            return product;
        }
    
        /**
         * 降级方法
         * 和需要受到保护的方法的返回值一致
         * 和需要受到保护的方法的参数列表一致
         *
         * @param id
         * @return
         */
        public Product orderFallBack(Long id) {
            Product product = new Product();
            product.setId(-1L);
            product.setProductName("熔断:降级");
            return product;
        }
    }
    

    3.4 配置默认的降级逻辑

    • OrderController.java
    package com.sunxiaping.controller;
    
    
    import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
    import com.sunxiaping.domain.Product;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    @RequestMapping(value = "/order")
    @DefaultProperties(defaultFallback = "defaultFallBack")
    public class OrderController {
        @Autowired
        private RestTemplate restTemplate;
    
    
        /**
         * 使用注解配置熔断保护
         * fallbackMethod:配置熔断之后的降级方法
         *
         * @param id
         * @return
         */
        @GetMapping(value = "/buy/{id}")
    //    @HystrixCommand(fallbackMethod = "orderFallBack")
        public Product buy(@PathVariable(value = "id") Long id) {
    
            Product product = restTemplate.getForObject("http://service-product/product/findById/" + id, Product.class);
    
            return product;
        }
    
        /**
         * 降级方法
         * 和需要受到保护的方法的返回值一致
         * 和需要受到保护的方法的参数列表一致
         *
         * @param id
         * @return
         */
        public Product orderFallBack(Long id) {
            Product product = new Product();
            product.setId(-1L);
            product.setProductName("熔断:降级");
            return product;
        }
        
        /**
         * 指定统一的降级方法
         * 参数:没有参数
         *
         * @return
         */
        public Product defaultFallBack() {
            Product product = new Product();
            product.setProductName("触发统一的降级方法");
            return product;
        }
    
    }
    

    3.5 超时设置

    • Hystrix的默认超时时间为1秒,我们可以通过如下的配置修改默认的超时设置:
    hystrix:
        command:
          default:
            execution:
              isolation:
                thread:
                  timeoutInMilliseconds: 6000 # 默认的连接超时时间为1秒,如果1秒没有返回数据,就自动触发降级逻辑
    
    • 当然,也可以在使用@HystrixCommand注解时配置超时设置:
    package com.sunxiaping.order.controller;
    
    
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
    import com.sunxiaping.order.domain.Product;
    import lombok.var;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    @RequestMapping(value = "/order")
    public class OrderController {
        @Autowired
        private RestTemplate restTemplate;
    
    
        /**
         * 使用OrderCommand调用远程远程服务
         *
         * @param id
         * @return
         */
        @GetMapping(value = "/buy/{id}")
        @HystrixCommand(fallbackMethod = "orderFallback", commandProperties = {
                @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
        })
        public Product buy(@PathVariable(value = "id") Long id) {
            return restTemplate.getForObject("http://service-product/product/findById/" + id, Product.class);
        }
    
    
        public Product orderFallback() {
            var product = new Product();
            product.setId(Long.MAX_VALUE);
            product.setProductName("熔断降级啦");
            
            return product;
        }
    
    }
    

    4 Feign实现服务降级

    Spring Cloud Feign默认已经为Feign整 合了Hystrix,所以添加Feign依赖后不用再添加Hystrix。feign中的hystrix默认是关闭的,需要在配置文件中开启。

    4.1 引入OpenFeign的依赖

    • 修改部分:
    <!-- openfeign -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
    • 完整部分:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>spring_cloud_demo</artifactId>
            <groupId>org.sunxiaping</groupId>
            <version>1.0</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>order-service-hystrix_feign9007</artifactId>
        <dependencies>
            <dependency>
                <groupId>org.springframework.retry</groupId>
                <artifactId>spring-retry</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!--   导入Eureka Client对应的坐标     -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <!-- openfeign -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
        </dependencies>
    </project>
    

    4.2 修改application.yml在Feign中开启Hystrix

    • application.yml
    feign:
      hystrix: # 开启Feign中的Hystrix
        enabled: true
    

    4.3 自定义Feign接口的实现类,这个实现类就是熔断触发的降级逻辑

    • ProductFeignClientCallBack.java
    package com.sunxiaping.feign.impl;
    
    import com.sunxiaping.domain.Product;
    import com.sunxiaping.feign.ProductFeignClient;
    import org.springframework.stereotype.Component;
    
    /**
     * 自定义Feign接口的实现类
     */
    @Component
    public class ProductFeignClientCallBack implements ProductFeignClient {
        @Override
        public Product findById(Long id) {
            Product product = new Product();
            product.setProductName("熔断降级了");
            return product;
        }
    }
    

    4.4 修改Feign接口添加降级方法的支持

    • 原先的Feign接口:
    package com.sunxiaping.feign;
    
    import com.sunxiaping.domain.Product;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value = "service-product")
    public interface ProductFeignClient {
    
        @GetMapping(value = "/product/findById/{id}")
        Product findById(@PathVariable(value = "id") Long id);
    
    }
    
    • 修改Feign接口添加降级方法的支持:
    package com.sunxiaping.feign;
    
    import com.sunxiaping.domain.Product;
    import com.sunxiaping.feign.impl.ProductFeignClientCallBack;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value = "service-product",fallback = ProductFeignClientCallBack.class)
    public interface ProductFeignClient {
    
        @GetMapping(value = "/product/findById/{id}")
        Product findById(@PathVariable(value = "id") Long id);
    
    }
    
  • 相关阅读:
    Spring MVC 核心组件详解
    Spring MVC 入门就这一篇
    Spring 事务解决方案
    【UGUI源码分析】Unity遮罩之Mask详细解读
    游戏开发中不同时区下的时间问题
    ARTS第十三周(阅读Tomcat源码)
    Win10 电脑安装.NET低版本提示“这台计算机中已经安装了 .NET Framwork 4.6.2或版本更高的更新”问题
    Dynamics 365 Setup 提示SqlServer 存在
    Dynamics CRM "Verification of prerequisites for Domain Controller promotion failed. Certificate Server is installed."
    Dynamics CRM
  • 原文地址:https://www.cnblogs.com/xuweiweiwoaini/p/13764543.html
Copyright © 2011-2022 走看看