• SpringCloud(十)服务雪崩与熔断Hystrix


     

     

     

     

    @author QYX 由于学习任务繁多,近期暂停了几天搬运,两天后恢复

    引入服务熔断Hystrix

    简单是来说,在分布式系统中,假如有一个请求需要调用A服务,但A服务出现了问题,则这个请求就会阻塞,那么只要调用服务A的请求都会阻塞,当阻塞的请求越来越多,占用的计算机资源就越来越多。进一步来说,就是一个服务出现问题,可能导致所有的请求都不可用,从而导致整个分布式系统都不可用,这就是“雪崩效应”。

    雪崩效应常见场景

    • 硬件故障:如服务器宕机,机房断电,光纤被挖断等。

    • 流量激增:如异常流量,重试加大流量等。

    • 缓存穿透:一般发生在应用重启,所有缓存失效时,以及短时间内大量缓存失效时。大量的缓存不命中,使请求直击后端服务,造成服务提供者超负荷运行,引起服务不可用。

    • 程序BUG:如程序逻辑导致内存泄漏,JVM长时间FullGC等。

    • 同步等待:服务间采用同步调用模式,同步等待造成的资源耗尽。

    雪崩效应应对策略

    针对造成雪崩效应的不同场景,可以使用不同的应对策略,没有一种通用所有场景的策略,参考如下:

    • 硬件故障:多机房容灾、异地多活等。

    • 流量激增:服务自动扩容、流量控制(限流、关闭重试)等。

    • 缓存穿透:缓存预加载、缓存异步加载等。

    • 程序BUG:修改程序bug、及时释放资源等。

    • 同步等待:资源隔离、MQ解耦、不可用服务调用快速失败等。资源隔离通常指不同服务调用采用不同的线程池;不可用服务调用快速失败一般通过熔断器模式结合超时机制实现。

    综上所述,如果一个应用不能对来自依赖的故障进行隔离,那该应用本身就处在被拖垮的风险中。 因此,为了构建稳定、可靠的分布式系统,我们的服务应当具有自我保护能力,当依赖服务不可用时,当前服务启动自我保护功能,从而避免发生雪崩效应。本文将重点介绍使用Hystrix解决同步等待的雪崩问题。

    服务隔离

    服务降级

    Hystrix:

    Hystrix [hɪst'rɪks],中文含义是豪猪,因其背上长满棘刺,从而拥有了自我保护的能力。本文所说的Hystrix是Netflix开源的一款容错框架,同样具有自我保护能力。为了实现容错和自我保护,下面我们看看Hystrix如何设计和实现的。

    Hystrix设计目标:

    • 对来自依赖的延迟和故障进行防护和控制——这些依赖通常都是通过网络访问的

    • 阻止故障的连锁反应

    • 快速失败并迅速恢复

    • 回退并优雅降级

    • 提供近实时的监控与告警

    Hystrix遵循的设计原则:

    • 防止任何单独的依赖耗尽资源(线程)

    • 过载立即切断并快速失败,防止排队

    • 尽可能提供回退以保护用户免受故障

    • 使用隔离技术(例如隔板,泳道和断路器模式)来限制任何一个依赖的影响

    • 通过近实时的指标,监控和告警,确保故障被及时发现

    • 通过动态修改配置属性,确保故障及时恢复

    • 防止整个依赖客户端执行失败,而不仅仅是网络通信

    Hystrix如何实现这些设计目标?

    • 使用命令模式将所有对外部服务(或依赖关系)的调用包装在HystrixCommand或HystrixObservableCommand对象中,并将该对象放在单独的线程中执行;

    • 每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)。

    • 记录请求成功,失败,超时和线程拒绝。

    • 服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求。

    • 请求失败,被拒绝,超时或熔断时执行降级逻辑。

    • 近实时地监控指标和配置的修改。

    Hystrix组件

    对RestTemplate的支持

    引入hystrix的依赖

    order_service

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

     

     

    在启动类中激活Hystrix

    order_service

     package qqq;
     
     import org.springframework.boot.SpringApplication;
     import org.springframework.boot.autoconfigure.SpringBootApplication;
     import org.springframework.boot.autoconfigure.domain.EntityScan;
     import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
     import org.springframework.cloud.client.loadbalancer.LoadBalanced;
     import org.springframework.context.annotation.Bean;
     import org.springframework.web.client.RestTemplate;
     
     @SpringBootApplication
     @EntityScan("com.qqq.entity")
     //@EnableFeignClients
     //激活hystrix
     @EnableCircuitBreaker
     public class OrderApplication {
         public static void main(String[] args) {
             SpringApplication.run(OrderApplication.class,args);
        }
         /**
          * eureka和consul都集成了Ribbon
          * 使用spring提供的RestTemplate发送http请求到商品服务
          * 1 将RestTemplate对象交给容器管理
          * 2 使用其方法完成操作
          */
         @LoadBalanced //Ribbon自带的负载均衡的注解
         @Bean
         public RestTemplate restTemplate()
        {
             return new RestTemplate();
        }
     
     
     }
     

    配置熔断触发的降级逻辑

    在order_service的controller中配置

        /**
          * 降级方法
          * 和需要收到保护的方法的返回值一致
          * 接口参数一致
          */
         public Product orderFallBack(Long id)
        {
             Product product=new Product();
             product.setProductName("触发降级方法");
             return product;
        }

    在需要受到保护的接口上使用@HystrixCommand配置

         @HystrixCommand(fallbackMethod = "orderFallBack")
         @RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
         public Product findById(@PathVariable("id") Long id)
        {
             Product product=null;
             product=productFeginClient.findById(id);
             return product;
        }

    注意事项:

    在之前的案例中,请求在超过1秒后都会返回错误信息,这是因为Hystrix的默认超时时长为1,我们可以通过配置修改这个值:

     hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMillisconds: 3000 #默认的连接超时为1s,如果1s没有返回数据,hystrix会自动触发降级逻辑

    配置统一的降级方法:

     package com.qqq.controller;
     
     import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
     import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
     import com.qqq.entity.Product;
     import com.qqq.fegin.ProductFeginClient;
     import org.springframework.beans.factory.annotation.Autowired;
     import org.springframework.cloud.client.ServiceInstance;
     import org.springframework.cloud.client.discovery.DiscoveryClient;
     import org.springframework.cloud.client.loadbalancer.LoadBalanced;
     import org.springframework.web.bind.annotation.PathVariable;
     import org.springframework.web.bind.annotation.RequestMapping;
     import org.springframework.web.bind.annotation.RequestMethod;
     import org.springframework.web.bind.annotation.RestController;
     import org.springframework.web.client.RestTemplate;
     
     import java.util.List;
     
     @RestController
     @RequestMapping("/order")
     /**
      * 指定公共的属性
      * 如果过在@DefaultProperties指定了公共的降级方法
      * 在@HystrixCommand不需要单独指定了
      *
      */
     @DefaultProperties(defaultFallback = "defaultFallBack")
     public class OrderController {
        //注入RestTemplate对象
        @Autowired
        private RestTemplate restTemplate;
        @Autowired
        private ProductFeginClient productFeginClient;
        /**
          * 使用注解配置熔断保护
          * fallbackmethod:配置熔断之后的降级方法
          * @param id
          * @return
          */
        @HystrixCommand
        @RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
        public Product findById(@PathVariable("id") Long id)
        {
            Product product=null;
            product=productFeginClient.findById(id);
            return product;
        }
        /**
          * 降级方法
          * 和需要收到保护的方法的返回值一致
          * 接口参数一致
          */
        public Product orderFallBack(Long id)
        {
            Product product=new Product();
            product.setProductName("触发降级方法");
            return product;
        }
        public Product defaultFallBack()
        {
            Product product=new Product();
            product.setProductName("触发统一的降级方法");
            return product;
        }
     }
     

     

  • 相关阅读:
    改变多行文本字符串的缩进
    多线程
    python基本语法2.5--字符串的相关操作
    python基本语法2.4---汉诺塔的递归
    python基本语法2.3--函数及参数传递
    python基本语法2.2--函数名当作变量传递
    python基本语法2.1--if判断和while,for循环
    AlexNet源码
    python基本语法1.4--初识爬虫
    python基本语法1.5--调用numpy库的性能影响
  • 原文地址:https://www.cnblogs.com/qyx66/p/12355310.html
Copyright © 2020-2023  润新知