20200523 尚硅谷2020最新版SpringCloud【笔记】2

尚硅谷2020最新版SpringCloud【笔记】2

10.Hystrix断路器

概述

微服务链路调用

扇出

服务雪崩

Hystrix 是一个用于处理分布式系统的延迟容错的开源库

能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性

向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常

Hystrix官宣,停更进维

Github 地址

主要功能

  • 服务降级
  • 服务熔断
  • 接近实时的监控

Hystrix重要概念

服务降级(fallback)

服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示,fallback

一般用于客户端,即服务消费者

哪些情况会触发降级

  • 程序运行异常
  • 超时
  • 服务熔断触发服务降级
  • 线程池/信号量打满也会导致服务降级

服务熔断(break)

类比保险丝,达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示

服务的降级->进而熔断->恢复调用链路

当失败的调用到一定阈值,默认是5秒内20次调用失败,就会启动熔断机制

img

服务限流(flowlimit)

秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行

降级容错解决的要求

  • 超时导致服务器变慢(转圈)
    超时不再等待
  • 出错(宕机或程序运行出错)
    出错要有兜底

Hystrix案例

服务生产者

  1. 建 Module,cloud-provider-hystrix-payment8001

  2. 改 POM

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

  4. 主启动类,添加注解 @EnableCircuitBreaker

  5. 服务降级,改业务服务类

    // 超时时间设置为 3s
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
    public String paymentInfo_TimeOut(Integer id) {
        // 程序异常
        int age = 10 / 0;
    
        // 超时
        // try {
        //     TimeUnit.MILLISECONDS.sleep(5000);
        // } catch (InterruptedException e) {
        //     e.printStackTrace();
        // }
    
        return "线程池:  " + Thread.currentThread().getName() + " id:  " + id + "\t" + "O(∩_∩)O哈哈~" + "  耗时(秒): ";
    }
    
    public String paymentInfo_TimeOutHandler(Integer id) {
        return "线程池:  " + Thread.currentThread().getName() + "  8001系统繁忙或者运行报错,请稍后再试,id:  " + id + "\t" + "o(╥﹏╥)o";
    }
    
  6. 服务熔断

    @HystrixCommand 注解中可配的属性位于 com.netflix.hystrix.HystrixCommandProperties

    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", commandProperties = {@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),// 是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),// 失败率达到多少后跳闸
    })
    public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
        if (id < 0) {
            throw new RuntimeException("******id 不能负数");
        }
        String serialNumber = IdUtil.simpleUUID();
    
        return Thread.currentThread().getName() + "\t" + "调用成功,流水号: " + serialNumber;
    }
    
    public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) {
        return "id 不能负数,请稍后再试,/(ㄒoㄒ)/~~   id: " + id;
    }
    

    localhost:8001//payment/circuit/1 返回正常,localhost:8001//payment/circuit/-1 会触发降级,多次触发降级后,访问正常 URL,发现返回的是降级后的响应,一段时间后,恢复正常。

服务消费者

  1. 建 Module,cloud-consumer-feign-hystrix-order80

  2. 改 POM,同上

  3. 改 YML

    feign:
      hystrix:
        enabled: true
    
  4. 主启动类,添加注解 @EnableHystrix

  5. 服务降级,Controller 调用 Feign 接口

    // 超时时间 2s
    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")})
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        // 程序异常
        // int age = 10 / 0;
    
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
    
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
        return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o  " + id;
    }
    
  6. 服务降级,Controller 全局服务降级

    @RestController
    @Slf4j
    @DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
    public class OrderHystirxController {
    	@Resource
        private PaymentHystrixService paymentHystrixService;
        
        @GetMapping("/consumer/payment/hystrix/timeout/{id}")
        @HystrixCommand
        public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
            // 程序异常
            // int age = 10 / 0;
    
            String result = paymentHystrixService.paymentInfo_TimeOut(id);
            return result;
        }
        
        public String payment_Global_FallbackMethod() {
            return "Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
        }
    }
    
  7. 服务降级,通配服务降级,针对 Feign 接口的调用

    1. 实现 Feign 接口
    @Component
    public class PaymentFallbackService implements PaymentHystrixService {
        @Override
        public String paymentInfo_OK(Integer id) {
            return "-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o";
        }
    
        @Override
        public String paymentInfo_TimeOut(Integer id) {
            return "-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o";
        }
    }
    
    1. Feign 接口添加注解属性 org.springframework.cloud.openfeign.FeignClient#fallback
    @Component
    @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT" ,fallback = PaymentFallbackService.class)
    public interface PaymentHystrixService {
        @GetMapping("/payment/hystrix/ok/{id}")
        public String paymentInfo_OK(@PathVariable("id") Integer id);
    
        @GetMapping("/payment/hystrix/timeout/{id}")
        public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
    }
    

服务熔断原理

熔断类型

  • 熔断打开
    请求不再进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入熔断状态
  • 熔断关闭
    熔断关闭不会对服务进行熔断
  • 熔断半开
    部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断

断路器开启或者关闭的条件

  1. 当满足一定阀值的时候(默认10秒内超过20个请求次数)
  2. 当失败率达到一定的时候(默认10秒内超过50%请求失败)
  3. 到达以上阀值,断路器将会开启
  4. 当开启的时候,所有请求都不会进行转发
  5. 一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。重复4和5

Hystrix工作流程

GitHub 地址

img

服务监控 Hystrix Dashboard

监控的微服务需要依赖 pring-boot-starter-actuator

创建步骤

  1. Module,cloud-consumer-hystrix-dashboard9001

  2. POM

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

  4. 主启动类,添加注解 @EnableHystrixDashboard

  5. 启动程序,访问 http://localhost:9001/hystrix

断路器演示

  1. 改造被监控的微服务

    /**
     *此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
     *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
     *只要在自己的项目里配置上下面的servlet就可以了
     */
    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
    
  2. 访问 http://localhost:9001/hystrix

  3. 填写 http://localhost:8001/hystrix.stream

11.zuul路由网关

跳过,可以看之前的视频:

尚硅谷经典SpringCloud框架开发教程全套完整版从入门到精通(大牛讲授spring cloud)

12.Gateway新一代网关

概述

Spring Cloud Gateway 使用的 Webflux 中的 reactor-netty 响应式编程组件,底层使用了 Netty 通讯框架

官网

Zuul

Gateway

主要功能

  • 反向代理
  • 鉴权
  • 流量控制
  • 熔断
  • 日志监控

对比 Zuul 和 Gateway

Zuul

Zuul 1进入维护阶段,Zuul 2 一直跳票

在 Spring Cloud F 版,推荐使用 Zuul

基于 Servlet 2.5 使用 阻塞 IO 架构

Gateway

Servlet 3.1 之后有了异步非阻塞的支持

Gateway 基于异步非阻塞模型

Spring Cloud Gateway 具有如下特性:

  • 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0 构建
  • 动态路由:能够匹配任何请求属性
  • 可以对路由指定 Predicate(断言)和 Filter(过滤器)
  • 集成 Hystrix 的断路器功能
  • 集成 Spring Cloud 服务发现功能
  • 请求限流功能
  • 支持路径重写

三大核心概念

Spring Cloud Gateway Diagram

  • Route(路由)

    路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由

  • Predicate(断言)

    参考的是java8的 java.util.function.Predicate 开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

  • Filter(过滤)

    指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。

核心逻辑

路由转发+执行过滤器链

入门案例

  1. Module,cloud-gateway-gateway9527

  2. POM

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    
  3. YML

    spring:
      application:
        name: cloud-gateway
      cloud:
        gateway:
          routes:
            - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
              uri: http://localhost:8001          #匹配后提供服务的路由地址
              predicates:
                - Path=/payment/get/**         # 断言,路径相匹配的进行路由
    
            - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
              uri: http://localhost:8001          #匹配后提供服务的路由地址
              predicates:
                - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
    
  4. 主启动类

  5. 测试

    直接访问原服务路径 localhost:8001/payment/get/1localhost:8001/payment/lb,可以成功

    通过网关访问服务 localhost:9527/payment/get/1localhost:9527/payment/lb,可以成功

编码方式配置

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
    RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
    routes.route("path_route_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
    return routes.build();
}

配置动态路由

默认情况下Gateway会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由

Predicate的使用

官网文档

配置的都是 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory 接口的实现类

Filter的使用

生命周期

  • pre

    在业务逻辑之前

  • post

    在业务逻辑之后

种类

自定义全局GlobalFilter

/**
 * 要求请求中带参数 uname,否则返回 406, "Not Acceptable"
 */
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("***********come in MyLogGateWayFilter:  " + new Date());

        String uname = exchange.getRequest().getQueryParams().getFirst("uname");

        if (uname == null) {
            log.info("*******用户名为null,非法用户,o(╥﹏╥)o");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

13.SpringCloud Config分布式配置中心

概述

官网文档

不同微服务应用的所有环境提供一个中心化的外部配置

SpringCloud Config 分为服务端和客户端

服务端也称为分布式配置中心,是一个独立的微服务应用

主要功能

  • 集中管理配置文件

  • 不同环境不同配置,动态化的配置更新,分环境部署比如dev/test/prod/beta/release

  • 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息

  • 当配置发生变动时,服务不需要重启即可感知到配置的变化并应用新的配置

  • 将配置信息以REST接口的形式暴露

    post、curl访问刷新均可....

Config服务端配置与测试

  1. Module,cloud-config-center-3344

  2. POM

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
    
  3. YML

    server:
      port: 3344
    
    spring:
      application:
        name:  cloud-config-center #注册进Eureka服务器的微服务名
      cloud:
        config:
          server:
            git:
    #          uri: git@github.com:liuxing5yu/config-repo.git #GitHub上面的git仓库名字
              uri: https://github.com/liuxing5yu/config-repo #GitHub上面的git仓库名字
          ####读取分支
          label: master
    
    #服务注册到eureka地址
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:7001/eureka
    
  4. 主启动类,添加注解 @EnableConfigServer

  5. 测试,访问 URL http://localhost:3344/master/configclient-dev.yml

配置读取规则

  • /{application}/{profile}[/{label}]
  • /{application}-{profile}.yml
  • /{label}/{application}-{profile}.yml
  • /{application}-{profile}.properties
  • /{label}/{application}-{profile}.properties

Config客户端配置与测试

  1. Module,cloud-config-client-3355

  2. POM

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    
  3. bootstrap.yml

    server:
      port: 3355
    
    spring:
      application:
        name: config-client
      cloud:
        #Config客户端配置
        config:
          label: master #分支名称
          name: configclient #配置文件名称
          profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
          uri: http://localhost:3344 #配置中心地址
    
    #服务注册到eureka地址
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:7001/eureka
    

    application.yml 是用户级的资源配置项

    bootstrap.yml 是系统级的,优先级更高

    Spring Cloud 会创建一个 Bootstrap Context,作为 Application Context 的父上下文。初始化的时候,Bootstrap Context 负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的 Environment。

    Bootstrap 属性有高优先级,默认情况下,它们不会被本地覆盖。Bootstrap Context 和 Application Context 有着不同的约定,所以新增 bootstrap.yml,保证配置分离。

    bootstrap.yml 先于 application.yml 加载。

  4. 业务类

    @RestController
    public class ConfigClientController {
        @Value("${my.name}")
        private String configInfo;
    
        @GetMapping("/configInfo")
        public String getConfigInfo() {
            return configInfo;
        }
    }
    
  5. 测试,http://localhost:3355/configInfo

    改变Git里配置的内容后,从3344服务端读取到更新后的内容,3355客户端仍然是改变前的内容

Config客户端之动态刷新

  1. POM

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
  2. YML

    # 暴露监控端点
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
  3. 业务类添加注解 @RefreshScope

  4. Git 更改后,发送 Post 请求,localhost:3355/actuator/refresh

posted @ 2020-05-23 14:24  流星<。)#)))≦  阅读(531)  评论(0编辑  收藏  举报