zoukankan      html  css  js  c++  java
  • Spring Cloud 核心组件——熔断降级

    今天先来说说“服务熔断”和“服务降级”。

    服务熔断:在股票市场,熔断这个词大家都不陌生,是指当股指波幅达到某个点后,交易所为控制风险采取的暂停交易措施。相应的,服务熔断一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施,所以很多地方把熔断亦称为过载保护。

    服务降级:大家都见过女生旅行吧,大号的旅行箱是必备物,平常走走近处绰绰有余,但一旦出个远门,再大的箱子都白搭了,怎么办呢?常见的情景就是把物品拿出来分分堆,比了又比,最后一些非必需品的就忍痛放下了,等到下次箱子够用了,再带上用一用。而服务降级,就是这么回事,整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。

    所以从上述分析来看,两者其实从有些角度看是有一定的类似性的:

    1)目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;

    2)最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;

    3)粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改);

    4)自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段;

    而两者的区别也是明显的:

    1)触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;

    2)管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)

    3)实现方式不太一样

    参考文章:https://blog.csdn.net/guwei9111986/article/details/51649240

    下面介绍 Hystrix:

    在分布式环境中,许多服务依赖项中的一些必然会失败。Hystrix 是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。Hystrix 通过隔离服务之间的访问点、停止级联失败和提供回退选项来实现这一点,所有这些都可以提高系统的整体弹性。

    Hystrix 提供了熔断、隔离、Fallback、Cache、监控等功能。出现错误之后可以 fallback 错误的处理信息,返回一些兜底数据等等。

    https://www.cnblogs.com/cjsblog/p/9391819.html

    本文的示例承接上一篇文章:https://www.cnblogs.com/jwen1994/p/11408511.html

    1. Feign 结合 Hystrix 断路器开发

    第一步:加入依赖

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

    注意新旧版本问题,所以要以官网为主,不然部分注解会丢失

    第二步:启动类里面增加注解 @EnableCircuitBreaker

    @SpringBootApplication
    @EnableFeignClients
    @EnableCircuitBreaker
    public class OrderServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderServiceApplication.class, args);
        }
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }

    我们也可以使用 SpringCloudApplication 注解,它包含了很多 Spring Cloud 相关的注解

    第三步:最外层 api 使用

    api 方法上增加 @HystrixCommand(fallbackMethod = "saveOrderFail")。好比异常处理(网络异常,参数或者内部调用问题)

    @RestController
    @RequestMapping("api/v1/order")
    public class OrderController {
    
        @Autowired
        private ProductOrderService productOrderService;
    
        @RequestMapping("save")
        @HystrixCommand(fallbackMethod = "saveOrderFail")
        public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){
    
            Map<String, Object> data = new HashMap<>();
            data.put("code", 0);
            data.put("data", productOrderService.save(userId, productId));
            return  data;
        }
    
        //注意,方法签名一定要要和api方法一致
        private Object saveOrderFail(int userId, int productId){
            Map<String, Object> msg = new HashMap<>();
            msg.put("code", -1);
            msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
            return msg;
        }
    }

    注意:编写 fallback 方法实现,方法签名一定要和 api 方法签名一致

    第四步:进行测试,我们使用一个会出错的请求,它会返回 saveOrderFail 的返回值

    2. 我们调用服务时,如果服务出错,我们希望可以进行一些处理

     第一步:开启 Feign 支持 Hystrix (注意,一定要开启,旧版本默认支持,新版本默认关闭)

    feign:
      hystrix:
        enabled: true

    第二步:FeignClient(name="xxx", fallback=xxx.class ),class 需要继承当前 FeignClient 的类

    @FeignClient(name = "product-service", fallback = ProductClientFallback.class)
    public interface ProductClient {
        @GetMapping("/api/v1/product/find")
        String findById(@RequestParam(value = "id") int id);
    }

    ProductClientFallback 类

    @Component
    public class ProductClientFallback implements ProductClient {
        @Override
        public String findById(int id) {
            System.out.println("feign 调用product-service findbyid 异常");
            return null;
        }
    }

    3. 进一步完善异常报警通知

    我们可以试着加入 Redis 来实现一个异常报警

    第一步:加入 Redis 依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    第二步:配置 Redis 链接信息

    spring:
      redis:
        database: 0
        host: 127.0.0.1
        port: 6379
        timeout: 2000

    第三步:修改代码

    @RestController
    @RequestMapping("api/v1/order")
    public class OrderController {
        @Autowired
        private ProductOrderService productOrderService;
    
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        @RequestMapping("save")
        @HystrixCommand(fallbackMethod = "saveOrderFail")
        public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId, HttpServletRequest request){
    
            Map<String, Object> data = new HashMap<>();
            data.put("code", 0);
            data.put("data", productOrderService.save(userId, productId));
            return  data;
        }
    
        //注意,方法签名一定要要和api方法一致
        private Object saveOrderFail(int userId, int productId, HttpServletRequest request){
            //监控报警
            String saveOrderKye = "save-order";
    
            String sendValue = redisTemplate.opsForValue().get(saveOrderKye);
            final String ip = request.getRemoteAddr();
            new Thread( ()->{
                if (StringUtils.isBlank(sendValue)) {
                    System.out.println("紧急短信,用户下单失败,请离开查找原因,ip地址是="+ip);
                    //发送一个http请求,调用短信服务 TODO
                    redisTemplate.opsForValue().set(saveOrderKye, "save-order-fail", 20, TimeUnit.SECONDS);
    
                }else{
                    System.out.println("已经发送过短信,20秒内不重复发送");
                }
    
            }).start();
    
            Map<String, Object> msg = new HashMap<>();
            msg.put("code", -1);
            msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
            return msg;
        }
    }

    4. Hystrix 降级策略和调整

    1)查看默认讲解策略 HystrixCommandProperties

    这个文件里可以看到所有默认的策略

    2)execution.isolation.strategy 隔离策略

    Hystrix 有两种隔离策略:THREAD 线程池隔离 (默认)、SEMAPHORE 信号量。信号量适用于接口并发量高的情况,如每秒数千次调用的情况,导致的线程开销过高,通常只适用于非网络调用,执行速度快

    3)execution.isolation.thread.timeoutInMilliseconds 超时时间

    Hystrix 默认超时时间为1000毫秒

    4)execution.timeout.enabled 是否开启超时限制 (一定不要禁用)

    Hystrix 默认是开启超时限制的

    5)execution.isolation.semaphore.maxConcurrentRequests 隔离策略为信号量的时候,如果达到最大并发数时,后续请求会被拒绝,默认是10

    #把hystrix超时时间禁用
    #hystrix:
    #  command:
    #    default:
    #      execution:
    #        timeout:
    #          enabled: false
    
    #execution.isolation.thread.timeoutInMilliseconds=4000
    
    #设置超时时间
    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 4000

    官方文档:https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.strategy

    5. 断路器 Dashboard 监控仪表盘

    生产环境几乎不用,只要做好异常告警就可以

    第一步:加入依赖

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>
    
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    第二步:启动类增加注解 @EnableHystrixDashboard

    第三步:配置文件增加 endpoint

    #暴露全部的监控信息
    management:
      endpoints:
        web:
          exposure:
            include: "*"

    第四步:访问入口

    1)访问:http://localhost:8781/hystrix

    2)Hystrix Dashboard 输入: http://localhost:8781/actuator/hystrix.stream

    参考资料:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-security-actuator

    补充: 如果从 Maven 中心仓库下载太慢,可是修改 Maven 仓库地址,使用其他 Maven 仓库。为了使用阿里云的仓库,我们在 pom.xml 中修改

    <repositories>
      <repository>
        <id>nexus-aliyun</id>
        <name>Nexus aliyun</name>
        <layout>default</layout>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
        <snapshots>
          <enabled>false</enabled>
        </snapshots>
        <releases>
          <enabled>true</enabled>
        </releases>
      </repository>
    </repositories>
  • 相关阅读:
    李宏毅2021春机器学习课程笔记——通过训练集上的Loss可获得的信息
    python学习-NotImplementedError的使用
    代码运行优化
    django实现上传文件读取文件内容
    django-admin上传下载文件
    AtCoder Beginner Contest 191 F
    敏感词过滤 AC自动机
    面经知识点
    select poll epoll实例
    socket用法
  • 原文地址:https://www.cnblogs.com/jwen1994/p/11432842.html
Copyright © 2011-2022 走看看