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>
  • 相关阅读:
    SD卡测试
    测试人员可能会遇到的问题
    HDU 1024 Max Sum Plus Plus
    HDU 1176 免费馅饼
    HDU 1257 最少拦截系统
    HDU 1087 Super Jumping! Jumping! Jumping!
    poj 1328 Radar Installation
    poj 1753 Flip Game
    HDU 1003 Max Sum
    HDU 5592 ZYB's Premutation(BestCoder Round #65 C)
  • 原文地址:https://www.cnblogs.com/jwen1994/p/11432842.html
Copyright © 2011-2022 走看看