zoukankan      html  css  js  c++  java
  • SpringCloud之Hystrix熔断降级(六)

    前言

      Hystrix是一个用于处理分布式系统的延迟容错和开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性

      “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障 监控(类似熔断保险丝),向调用方返回一个符合预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

    服务熔断

      熔断机制是应对雪崩效应的一种微服务 链路保护机制;

      当扇出链路的某个服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回“错误”的响应信息,当检测到该节点微服务调用响应正常后 恢复调用链路,在springcloud框架里熔断机制通过Hystrix实现,Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒20次调用失败就会启动熔断机制,熔断机制的注解是@HystrixCommand

    服务降级

      整体资源快不够用了,忍痛将某些服务先关掉,待度过难关,在开启回来。

      所谓降级,就是一般是从整体符合考虑,就是当某个服务熔断之后,服务器将不再被调用,此刻客户端可以自己准备一个本地的fallback回调,返回一个缺省值,这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强。

    服务熔断环境搭建

    1. 创建springcloud-provider-dept-hystrix-8001服务提供者

    ① 修改pom依赖,和springcloud-provider-dept-8001中的pom相同,复制过来 然后添加Hystrix依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>

    ② 编写application.ym配置文件

    server:
      port: 8001                                         # 当前微服务的端口
    
    mybatis:
      config-location: classpath:mybatis/mybatis-config.xml # mybatis配置文件所在路径
      type-aliases-package: com.common.springcloud.entity    # 所有饿entity实体类所在包
      mapper-locations:
        - classpath:mybatis/mapper/*.xml                # mapper映射文件
    
    spring:
      application:
        name: springcloud-provider-dept-hystrix            # 对外暴露的微服务的名字(很重要)
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource      # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver        # mysql驱动包
        url: jdbc:mysql://localhost:3306/db01?useUnicode=true&serverTimezone=GMT%2B8&characterEncoding=UTF-8&useSSL=false        # 数据库名称
        username: root
        password: 123456
      druid:
        # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个,
        #注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串
        test-on-borrow: false
        # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
        #注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串
        test-while-idle: true
        # 指明是否在归还到池中前进行检验,注意: 设置为true后如果要生效,
        #validationQuery参数必须设置为非空字符串
        test-on-return: false
        # SQL查询,用来验证从连接池取出的连接,在将连接返回给调用者之前.
        #如果指定,则查询必须是一个SQL SELECT并且必须返回至少一行记录
        validation-query: select 1
    
    eureka:
      client:   #客户端注册进eureka服务列表内
        service-url:
          defaultZone: http://eureka1:7001/eureka/,http://eureka2:7002/eureka/,http://eureka3:7003/eureka/      #去注册中心的地址
          #defaultZone:7001,7002,7003 去注册中心的地址
      instance:
        instance-id: springcloud-dept-hystrix8001   #自定义hystrix相关的服务名称信息
        prefer-ip-address: true                         #访问路径可以显示ip地址
    
    info:
      app.name: wj-springcloud
      company.name: www.wj.com
      build.artifactId: $project.artifactId$
      build.version: $project.version$                   

    ③ 在相关类添加注解

    Controller类

    package com.yt.springcloud.controller;
    import java.util.List;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.discovery.DiscoveryClient;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import com.yt.springcloud.entity.Dept;
    import com.yt.springcloud.service.impl.DeptService;
    
    @RestController//整合了responceBody+Controller
    public class DeptController {
    
        @Autowired
        private DeptService service = null;
    
        @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
        //一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
        @HystrixCommand(fallbackMethod = "processHystrix_Get")//发生异常的时候,会调用这个fallbackmethod方法,去处理
        public Dept get(@PathVariable("id") Long id){
    
            Dept dept = this.service.get(id);
            
            if (null == dept) {
                throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
            }
            
            return dept;
        }
    
        /**
         * 发生异常的时候,会调用这个方法来处理,还是返回一个dept对象,但是里面的信息是我们自定义的
       * 下面的链路赋值形式:new ObjectTest().setXX().setXX().....; 需要导入lombok依赖即可 *
    @param id * @return */ public Dept processHystrix_Get(@PathVariable("id") Long id){ return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand") .setDb_source("no this database in MySQL"); } }

    ApplicationBoot启动类

    package com.yt.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient //本服务启动后会自动注册进eureka服务中
    @EnableDiscoveryClient //服务发现
    @EnableCircuitBreaker//对hystrixR熔断机制的支持!!!
    public class DeptProvider8001_Hystrix_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
        }
    }
     

    测试

    启动Eureka服务注册服务,如果搭建了集群,全部启动也可。

    启动Hystrix服务提供者服务

    启动服务消费者


     打开注册Eureka页面:http://localhost:7001/  #打开自己设置URL即可

    进行接口调用

    测试id为1,数据是OK的

    当的id不存在的时候,会进入容错的方法,返回刚刚设置的返回值


    服务降级环境搭建

      服务降级处理是在客户端完成的,与服务端没有关系

      修改springcloud-api工程,根据已经有的DeptClientService接口新建一个实现了FallbackFactory接口的类DeptClientServiceFallbackFactory

    package com.yt.springcloud.service;
    import java.util.List;
    import org.springframework.stereotype.Component;
    import com.yt.springcloud.entity.Dept;
    import feign.hystrix.FallbackFactory;
    @Component
    public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
    {
        @Override
        public DeptClientService create(Throwable throwable)
        {
            return new DeptClientService() {
                @Override
                public Dept get(long id)
                {
                    return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭")
                            .setDb_source("no this database in MySQL");
                }
    
                @Override
                public List<Dept> list()
                {
                    return null;
                }
    
                @Override
                public boolean add(Dept dept)
                {
                    return false;
                }
            };
        }
    }

    修改springcloud-api工程,DeptClientService接口在注解@FeignClient

    import com.common.springcloud.pojo.Dept;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import java.util.List;
    //@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")//针对于更细粒化的控制,针对哪一个微服务进行面向接口的feign的
    @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT", fallback = DeptClientServiceFallbackFactory.class)
    public interface DeptClientService {
        @GetMapping("/dept/get/{id}")
        public Dept queryId(@PathVariable("id") Long id);
    
        @GetMapping("/dept/list")
        public List<Dept> queryAll();
    
        @PostMapping("/dept/list")
        public boolean addDept(Dept dept);
    }

    修改springcloud-consumer-dept-feign工程的application.yml配置文件

    测试

    1. 启动3个Eureka

    2. 微服务springcloud-provider-dept-8001启动

    3. springcloud-consumer-dept-feign启动

    4. 正常访问测试: http://localhost/consumer/dept/get/1

    5. 故意关闭微服务springcloud-provider-dept-8001

    6. 客户端(消费者)自己调用提示

     

    此时服务端provider已经down了,但是我们做了服务降级处理,让客户端不可用时也会获得提示信息而不会挂起耗死服务器。

    可以看做是服务提供者的一个应急策略,返回服务坏掉的信息。

  • 相关阅读:
    查看pip install *.whl 支持的文件版本
    spark Infinate 的处理
    nc 文件的nan识别
    mysql 存中文失败问题
    tensorflow 安装
    数据库存含中文的json 时避免存成中文的ascii
    python 继承中的__init__
    python mysql数据库中 json的存储
    python 版本配置问题
    python dict 实现swich
  • 原文地址:https://www.cnblogs.com/FondWang/p/12254764.html
Copyright © 2011-2022 走看看