SpringCloud 微服务分布式 应用笔记(三)

2024-08-06 14:01:48 浏览数 (3)

SpringCloud 应用笔记

服务熔断Hystrix入门

雪崩效应

在微服务架构中,一个请求需要调用多个服务是非常常见的。**但!!**

如客户端访问A服务,而A服务需要调用B 服务,B服务需要调用C服务

但!!

  • 如果,由于网络原因或者自身的原因: B服务或者C服务不能及时响应 A服 务将处于阻塞状态,直到B服务C服务响应。
  • 此时若有大量的请求涌入,容器的线程资源会被消耗完毕 导致服务瘫痪。
  • 服务与服务之间的依赖性,故障会传播,造成连锁反应, 会对整个微服务系统造成灾难性的严重后果 这就是服务故障的“雪崩”效应。

雪崩是系统中的蝴蝶效应导致其发生的原因多种多样:

  • 有不合理的容量设计
  • 亦或是某台机器的资源耗尽。
  • 或者是高并发下某一个方法响应变慢
  • 硬件问题,这感觉只能说是点背了⊙︿⊙
  • 缓存击穿,导致调用全部访问某服务,导致down掉

  • 我们无法完全杜绝雪崩源头的发生,但是**雪崩的根本原因来源于服务之间的强依赖** 所以我们可以提前评估,做好:**熔断**,**隔离**,**限流。** 避免雪崩的产生~

避免雪崩的产生

服务隔离
  • 顾名思义,它是指将系统按照一定的原则划分为若干个服务模块:**各个模块之间相对独立,无强依赖。**
  • 当有故障发生时 能将问题和影响隔离在某个模块内部 而不扩散风险,不波及其它模块,不影响整体的系统服务。
熔断降级
  • 熔断这一概念来源于电子工程中的断路器(Circuit Breaker) 电压高~保险丝断~跳闸~保护电器 在互联网系统中,当下游服务因访问压力过大而响应变慢或失败 上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。
  • 在客户端控制对依赖的访问,如果调用的依赖不可用时,则不再调用,**直接返回错误,或者降级处理。** 所谓降级,就是当某个服务熔断之后,服务器将不再被调用 此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值.也可以理解为 兜底 fallback回调方法是对你目前请求失效后的一个解决方案:
  • 开源的库比如**hystrix** 很好的实现了熔断和降级的功能。 他的主要思想是,设置一些阀值,比如,最大并发数,错误率百分比,熔断尝试恢复时间等。 通过这些阀值来转换熔断器的状态: 1.关闭状态允许调用依赖 2.打开状态不允许调用依赖,直接返回错误,或者调用fallback 3.半开状态,根据熔断尝试恢复时间来开启,允许调用依赖,如果调用成功则关闭失败则继续打开
服务限流
  • 限流可以认为服务降级的一种 限流就是限制系统的输入和输出流量已达到保护系统的目的。
  • 一般来说系统的吞吐量是可以被测算的 一旦检测达到的限制的阈值,就限制流量访问并采取少量措施以完成限制流量的目的。
  • 限制客户端的调用来达到限流的做法是很常见的 比如,我们限制每秒最大处理200个请求,超过个数量直接拒绝请求。
  • 推迟解决,拒绝解决,或者者部分拒绝解决等等。
  • 常见的算法如令牌桶算法

Hystrix介绍

logo:**非洲的一个动物, 豪猪~我也不知道为啥..就很nice~**

Hystrix是由**Netflflix开源的**一个**延迟和容错库**

用于隔离访问远程系统、服务或者第三方库,防止级联失败: 从而提升系统的可用性与容错性。

  • 在分布式系统中,每个服务都可能会调用很多其他服务 被调用的那些服务就是依赖服务,有的时候某些依赖服务出现故障也是很正常的。
  • Hystrix可以让我们在分布式系统中对服务间的调用进行控制,加入一些调用延迟或者依赖故障的**容错机制.**
  • Hystrix通过将依赖服务进行资源隔离,进而组织某个依赖服务出现故障的时候 这种故障在整个系统所有的依赖服务调用中进行蔓延时 Hystrix还提供故障时的fallback降级机制
  • 总而言之,Hystrix通过这些方法帮助我们提升分布式系统的可用性和稳定性

Hystrix主要通过以下几点实现: 延迟 容错

包裹请求:
  • 使用**HystrixCommand包裹** 对依赖的调用逻辑包裹,**使每个命令在独立线程中执行。 一般来说是对于经常使用的方法进行包裹~ 不是很长调用的并不需要进行包裹~** 也对 Hystrix 也主要是做熔断的…**防止雪崩**对于不经常使用的方法也不会**崩坏**
跳闸机制:
  • 当某 包裹 服务的错误率超过一定的阈值时,
  • Hystrix可以**自动**或**手动跳闸**,停止请求:服务一段时间 错误率:当请求满足一定的数量默认20 且请求失败比例的大于 50% Hystrix就会使服务暂时的停止...  使服务冷静一段时间, 这段时间都是响应一个可正常运行的fallback方法, 并不会让你的程序卡在这儿… 等过一段时间, 又会自动的又将 服务打开~让你进行访问… 整个过程都是自动的!
资源隔离:
  • Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)
  • 如果该线程池已满发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。(也是保护服务正常运行的一种形式...) 下面的 Hystrix监控就是靠着这些线程需要进行的操作..
监控:
  • Hystrix可以近乎实时地监控运行指标和配置的变化 例如成功、失败、超时、以及被拒绝的请求等。
  • 甚至还提供一个图表, 供运维人员可以实时的看图, 就了解了当前程序的状态
回退机制:
  • 当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。  回退逻辑由开发人员自行提供,例如返回一个缺省值。
  • 自我修复: 断路器打开一段时间后,会自动进入“半开”状态。 半开状态: 有可能之后变为打开, 有可能是关闭状态; 半开状态对当前情况一种分析,来觉得之后的状态情况!

Rest 实现服务熔断 实战!

ok, 终于经过了上面 乱七八糟,令人头疼的理论终于到了代码了…

  • 目前我们简单的了解了: 什么是雪崩 熔断 降级
  • 接下来就让我们通过 Rest方式实现 处理雪崩的 熔断降级 rest 是调用方请求的一种方式…Hystrix 一般对调用方的方法进行 包裹监视 如果出现问题进行降级 fallback**处理**

在之前项目基础上更改: 不了解同学可以点击这儿!!**耐心学习~**

公工配置:

严格遵循了SpringCloud的 三板斧原则:依赖 配置 注解

首先还是万变不离其宗的依赖 pom.xml

pom.xml

代码语言:javascript复制
<!-- hystrix实现服务熔断 -->
<!-- 熔断器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- SpringCloud 对hystrix 的starter全部依赖集成...  -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
如果需要对状态进行实时的监视配置 还需配置.yml

.yml

代码语言:javascript复制
#不在任何节点写属性,它就是首级...
management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream     # hystri流文件实时监控的文件
        #stream流: 配置这个表示状态信息已流的方式 实时进行记录;
  • 这个 .yml不是强求! 如果不需要实时的监控可以不要
  • 通过下面的: 接口就可以访问当然 包裹方法的执行状态! http://localhost:对应调用者端口/actuator/hystrix.stream 本人这里都是已学习为主的,所以都是localhost本地的ip
主程序类需要提供一个注解:

主程序类, 几乎不要任何的配置!就只要一个注解:

  • @EnableCircuitBreaker 表示, 开启Hystrix的熔断降级!

接下来介绍 熔断降级的两种实现~ controller层进行的修改! 在最顶上进行的**降级!**


默认一个服务降级 @HystrixCommand

  • @HystrixCommand声明在一个要**包裹的controller请求方法上!**
  • fallbackMethod = "指定的降级方法" 并通过 fallbackMethod 属性指定一个降级方法 当原方法出现异常, 则会直接执行 降级方法.
  • 降级方法, 是一个除了方法名以外一切和 包裹方法**一模一样的方法!!** 参数 参数类型 返回值 修饰符! ~类型真的坑我就写错成 int 和 Integer找了半天的错~

UserController.Java

代码语言:javascript复制
//编程控制层,接受请求响应结果
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/showUserOrder")                               //页面请求的方法名,get方式请求!
    @HystrixCommand(fallbackMethod = "showUserOrderFallBack")   //给方法指定一个局部熔断方法;
    public List<Order> showUserOrder(Integer uid){

        int num = (int) (Math.random() * 10);   //这里为了方便看到效果,本人决定手动随机抛出异常! 70%几率
        System.out.println(num);
        if (num > 7) {
            throw new RuntimeException();       //主动对外抛出异常...
        }

        return userService.currentUserOrder(uid);
        //Service又是通过网络调用  订单模块来响应的结果,因此在此基础上要缺点订单模块是运行中的...
    }
    //局部熔断器方法...方法名外: 一模一样
    public List<Order> showUserOrderFallBack(Integer uid){
        //这里主要做的就是对请求的一种处理,方法: 假的数据....
        System.out.println("局部熔断方法");
        List<Order> list = new ArrayList<>();
        list.add(new Order(0, "进入熔断降级方法", 0.0, uid));
        return list;
    }
}

类全局 服务降级 @DefaultProperties

  • @DefaultProperties 一般上面在类上:
  • 并通过**defaultFallback = "全局的降级方法"** 指定全局的**降级处理** 类中任一个报错都会进入该方法
  • 与全局不同的是**实现的降级方法** 不在需要一模一样…因为你也不知道要啥参数 返回值了… 需要注意: 虽然@DefaultProperties在类上声明了 还是要给 要降级的方法上声明 @HystrixCommand但是不用在指定降级方法了!!

UserController.Java

代码语言:javascript复制
//编程控制层,接受请求响应结果
@RestController
@DefaultProperties(defaultFallback = "commonFallBack")     //全局熔断器 (如有控制器抛出异常直接进到这个方法)
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/showUserOrder")                                 //页面请求的方法名,get方式请求!
    @HystrixCommand//(fallbackMethod = "showUserOrderFallBack")   //给方法指定一个局部熔断方法;
    public List<Order> showUserOrder(Integer uid){

        int num = (int) (Math.random() * 10);   //这里为了方便看到效果,本人决定手动随机抛出异常! 70%几率
        System.out.println(num);
        if (num > 7) {
            throw new RuntimeException();       //主动对外抛出异常...
        }
        return userService.currentUserOrder(uid);
    }

//    //局部熔断器方法...方法名外: 一模一样
//    public List<Order> showUserOrderFallBack(Integer uid){
//        //这里主要做的就是对请求的一种处理,方法: 假的数据....
//        System.out.println("局部熔断方法");
//        List<Order> list = new ArrayList<>();
//        list.add(new Order(0, "进入熔断降级方法", 0.0, uid));
//        return list;
//    }

    //全局熔断器方法... 因为是全局的所以参数就不好提供了;
    public List<Order> commonFallBack(){
        System.out.println("全局熔断方法");
        List<Order> list = new ArrayList<>();
        list.add(new Order(0, "全局熔断方法", 0.0, 1));
        return list;
    }
}

总结:

  • 三板斧~
  • 熔断主要做的是类似**异常处理的**, 不一定在调用方写的!
  • pom.xml 导入对应依赖
  • 如果要实时记录数据需要做的 .yml 配置
  • 主程序的启动注解 @EnableCircuitBreaker
  • 根据需求场景来决定: 局部/全局降级策略!!!

Hystrix的监控平台

Hystrix 对降级操作提供一个监控器平台

  • Hystrix官方还提供了基于图形化的DashBoard(仪表板)监控平台。
  • Hystrix仪表板可以显示每个断路器(被@HystrixCommand注解的方法)的状态。

主要作用是:

  • 主要作用就是针对上面, .yml 配置的监控文件, 它可以对文件进行监视.
  • 并产生图形化的页面给开发人员更方便的观看**实时的数据**!! 毕竟 没人喜欢一直盯着这个满屏的子 瞅!

    1 人点赞