微服务雪崩保护

一.微服务雪崩问题

一.分布式系统问题

由于网络的不稳定性,决定了任何一个服务的可用性都不是 100% 的。当网络不稳定的时候,作为服务的提供者,自身可能会被拖死,导致服务调用者阻塞,最终可能引发雪崩效应。

二.可能产生雪崩的原因:

1.服务不可用:缓存击穿、大量的请求、程序bug、硬件故障、资源耗尽等导致服务不可用
2.流量过大:由于用户或者代码逻辑重试

三.现象:

1.开始线程1中微服务D不可用了,线程1阻塞在微服务D
2.线程2中,由于微服务C依赖于不可用的微服务D,那么导致微服务C也不可用,线程2阻塞在微服务C中
3.以此类推,该链路上的微服务都会变得不可用,产生雪崩效应。
在这里插入图片描述
一个微服务故障导致整个链路的微服务都故障(链路连锁故障)。

四.常用解决方法:

1.超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待
2.仓壁模式:限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。
3.熔断降级:由断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。
4.流量限流:限制业务访问的QPS,避免服务因流量的突增而故障。

二.Sentinel

一.Sentinel工具和Hystrix对比

SentinelHystrix
隔离策略信号量隔离线程池隔离/信号量隔离
熔断降级策略基于慢调用比例或异常比例基于失败比率
实时指标实现滑动窗口滑动窗口(基于 RxJava)
规则配置支持多种数据源支持多种数据源
扩展性多个扩展点插件的形式
基于注解的支持支持支持
限流基于 QPS,支持基于调用关系的限流有限的支持
流量整形支持慢启动、匀速排队模式不支持
系统自适应保护支持不支持
控制台开箱即用,可配置规则、查看秒级监控、机器发现等不完善
常见框架的适配Servlet、Spring Cloud、Dubbo、gRPC 等Servlet、Spring Cloud Netflix
Sentinel是阿里巴巴的流量控制开源技术框架,Hystrix已经不维护了。
Sentinel:
丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

二.安装启动Sentinel

1.GitHUb下载Sentinel官服提供的jar包
在这里插入图片描述
2.命令启动

java -jar sentinel-dashboard-1.8.1.jar

或者

java -Dserver.port=8090 -jar sentinel-dashboard-1.8.1.jar

3.访问localhost:8080,用户名密码都是sentinel

三.spring-cloud整合

在这里插入图片描述

1.引入依赖到order-service

<!--sentinel-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>

2.配置order-service的yaml

server:
  port: 8088
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: 159735
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.136.160:8848
    sentinel:
      transport:
        dashboard: localhost:8080

#        namespace: 4d6ce343-9e1b-44df-a90f-2cf2b6b3d177 # dev环境
#        ephemeral: false # 是否是临时实例
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule  # 负载均衡规则
ribbon:
  eager-load:
    enabled: true # 开启饥饿加载
    clients: # 指定饥饿加载的服务名称
      - userservice
feign:
  httpclient:
    enabled: true # 支持HttpClient的开关
    max-connections: 200 # 最大连接数
    max-connections-per-route: 50 # 单个路径的最大连接数

3.父工程的依赖springBoot、SpringCloud、AlibbCloud版本一定要对应上

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.itcast.demo</groupId>
    <artifactId>cloud-sentinel</artifactId>
    <version>1.0</version>
    <modules>
        <module>user-service</module>
        <module>order-service</module>
        <module>feign-api</module>
        <module>gateway</module>
    </modules>

    <packaging>pom</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <mysql.version>5.1.47</mysql.version>
        <mybatis.version>2.1.1</mybatis.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- springCloud -->
<!--            阿里巴巴Cloud-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.5.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- mysql驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!--mybatis-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

三.雪崩保护措施

一.超时处理

设置超时时间,超过一定时间返回错误信息,这个是最常用的,但对客户很不友好。
在这里插入图片描述

二.仓壁模式

类似于一艘船破损,只有部分舱门进水,每个舱门相互独立。限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。
在这里插入图片描述
业务A和业务B共用一个线程池,如果业务A调用的微服务B产生异常,会影响整个线程池连接。如果使用线程隔离,一个业务的线程池产生异常,不会影响其他业务,舱壁模式降低依赖服务对整个系统的影响,保护有限的资源不被耗尽,增加了系统得到弹性。

常用的两种隔离方式:
线程池隔离:给每个服务调用业务分配一个线程池,利用线程池本身实现隔离效果

信号量隔离:不创建线程池,而是计数器模式,记录业务使用的线程数量,达到信号量上限时,禁止新的请求。信号量隔离是用Semaphore控制的

信号量隔离线程隔离
优点轻量级,无额外开销支持主动超时,支持异步调用
缺点不支持主动超时和异步调用线程额外开销比较大
场景高频调用,高扇出低扇出

三.限流

控制流量:限制业务访问的QPS,避免服务因流量的突增而故障。是雪崩的预防措施。

手段

1.计数器算法:存在临界点问题。
2.滑块算法:就是包含多个计数器算法,所需内存较大。
3.漏桶算法:漏桶算法能够强行限制数据的传输速率。
4.令牌漏桶算法: 令牌桶算法能够在限制数据的平均传输速率的同时还允许某种
程度的突发传输。
5.簇点链路:对controller的监控。

漏桶和令牌对比:在某些情况下,漏桶算法不能够有效地使用网络资源。因为漏桶的漏出速率是固定的,所以即使网络中没有发生拥塞,漏桶算法也不能使某一个单独的数据流达到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。而令牌桶算法则能够满足这些具有突发特性的流量。通常,漏桶算法与令牌桶算法结合起来为网络流量提供更高效的控制。

四.熔断降级

一.服务熔断:
考试过程中当断则断的方式,正好符合微服务架构中的一种安全机制:熔断
在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。
二.服务降级:
当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。
在这里插入图片描述
三.熔断的状态:
1.closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态
2.open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态5秒后会进入half-open状态
3.half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。

  • 请求成功:则切换到closed状态
  • 请求失败:则切换到open状态
    在这里插入图片描述

四.簇点链路限流测试

簇点链路: 当请求进入微服务时,首先会访问DispatcherServlet,然后进入Controller、Service、Mapper,这样的一个调用链就叫做簇点链路。簇点链路中被监控的每一个接口就是一个资源

默认情况下sentinel会监控SpringMVC的每一个端点(Endpoint,也就是controller中的方法),因此SpringMVC的每一个端点(Endpoint)就是调用链路中的一个资源。

一.流控模式

在添加限流规则时,点击高级选项,可以选择三种流控模式

  • 直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式
  • 关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
  • 链路:统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流
    在这里插入图片描述
    QPS(TPS):每秒钟request/事务数量= 并发数/平均响应时间

二.测试限流模式

一.直接模式测试

1.给资源/order/query新增限流规则,阈值为5
在这里插入图片描述
2.使用JMeter测试,线程数20,2秒内,循环1次,QPS为10,超过了设置的5
在这里插入图片描述
结果20次请求,2秒内只有4个请求成功
在这里插入图片描述

二.关联模式测试

1.给资源/order/query关联/order/update,新增限流规则,阈值为5,如果资源/order/update 请求次数到达阈值5,/order/query请求失败
在这里插入图片描述
2.query和update两个请求,设置1000个用户,100秒,QPS为1000/100=10,超过了设置的阈值5
在这里插入图片描述
结果order/update达到阈值,order/query请求失败
在这里插入图片描述
在这里插入图片描述

二.链路模式测试

1.分别用order/query和order/save的controller调用service层的queryGoods方法,该方法需要通过注解来被Sentinel监控
在这里插入图片描述
2.链路模式中是对不同来源的链路进行监控,sentinel默认会给进入SpringMVC的所有请求设置同一个root资源,会导致链路模式失效。
需要关闭这种对SpringMVC的资源聚合,修改order-service服务的application.yml文件:

spring:
  cloud:
    sentinel:
      web-context-unify: false # 关闭context整合

重启服务然后分别请求发现goods资源添加上了,记得Sentinel依赖版本要1.8.0以上才生效
在这里插入图片描述
3.随便点击一个goods资源后面的流控按钮,因为是同一资源,设置阈值为2,统计从这个路口进入的
在这里插入图片描述
4.设置线程数200,时间50秒,那么QPS就是4,超过设置的阈值2
在这里插入图片描述
5.由于QSP是4,设置的是2,所以一直有两个请求query请求失败
在这里插入图片描述

三.流控效果

流控效果是指请求达到流控阈值时应该采取的措施,包括三种:

  • 快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。

  • warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。

  • 排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长

四.测试控流效果

一.快速失败

上面测试限流模式都是用快速失败

二.warm up

阈值一般是一个微服务能承担的最大QPS,但是一个服务刚刚启动时,一切资源尚未初始化(冷启动),如果直接将QPS跑到最大值,可能导致服务瞬间宕机。

warm up也叫预热模式,是应对服务冷启动的一种方案。请求阈值初始值是 maxThreshold / coldFactor,持续指定时长后,逐渐提高到maxThreshold值。而coldFactor的默认值是3.

在这里插入图片描述
1.配置控流规则:给/order/query这个资源设置限流,最大QPS为10,利用warm up效果,预热时长为5秒
在这里插入图片描述
2.设置JMeter:线程数200,时间20秒,所以QPS是10,等于设置的阈值10
在这里插入图片描述
3.结果:刚开始失败请求多然后成功请求逐渐趋于平稳,最后都成功
在这里插入图片描述
4.去Sentinel控制台查看实时监测
在这里插入图片描述

三.排队等待

排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝。

例如:QPS = 5,意味着每200ms处理一个队列中的请求;timeout = 2000,意味着预期等待时长超过2000ms的请求会被拒绝并抛出异常。

比如现在一下子来了12 个请求,因为每200ms执行一个请求,那么:

  • 第6个请求的预期等待时长 = 200 * (6 - 1) = 1000ms
  • 第12个请求的预期等待时长 = 200 * (12-1) = 2200ms

1.配置控流规则:设置阈值为10,超时时间5秒
在这里插入图片描述
2.设置JMeter参数:线程数300,时间20,所以QPS是15,超过阈值10。超出的请求会失败
在这里插入图片描述
3.结果:开始都请求成功了,中间超出部分放在队列中,队列满了会请求失败
在这里插入图片描述

4.查看Sentinel的实时监控
在这里插入图片描述

五.热点参数限流

一.介绍

热点参数限流是分别统计参数值相同的请求,判断是否超过QPS阈值。
在这里插入图片描述
热点参数限流会根据参数值分别统计QPS,当id=1的请求触发阈值被限流时,id值不为1的请求不受影响。

参数QPS
id=13
id=21

二.热点限流测试

一.标记资源

给order-service中的OrderController中的/order/{orderId}资源添加注解:
在这里插入图片描述

二.热点参数限流规则

给/order/{orderId}这个资源添加热点参数限流,规则如下:

•默认的热点参数规则是每1秒请求量不超过2

•给102这个参数设置例外:每1秒请求量不超过4

•给103这个参数设置例外:每1秒请求量不超过10

在这里插入图片描述

三.配置JMeter参数

线程数500,时间100秒,所以QPS是5,超过参数101、102设置的阈值2,不超过参数103的阈值10
在这里插入图片描述

四.结果

JMeter设置的QPS是5,参数101阈值是2,参数102阈值是4,参数103阈值是10,结果通过的请求效果如下
在这里插入图片描述
热点限流是针对某个资源的参数进行限流,一般用于限时秒杀等,也很鸡肋

六.FeignClient整合Sentinel降级

我们的微服务远程调用都是基于Feign来完成的,因此我们需要将Feign与Sentinel整合,在Feign里面实现线程隔离和服务熔断。

一.修改配置,开启sentinel功能

修改OrderService的application.yml文件,开启Feign的Sentinel功能:

feign:
  sentinel:
    enabled: true # 开启feign对sentinel的支持

二.编写失败降级逻辑

给FeignClient编写失败后的降级逻辑

①方式一:FallbackClass,无法对远程调用的异常做处理

②方式二:FallbackFactory,可以对远程调用的异常做处理,我们选择这

一.在feign中编写一个服务

在这里插入图片描述

二.注册bean

在这里插入图片描述

三.在FeignClient中使用

在这里插入图片描述
要注意啊,因为feign-api这个是被order服务依赖,所有应该让order的主方法,扫到feign项目的对象,这个FallBackFactory工厂才能被注册上

四.访问一次订单

就设置好降级服务了,待会进行熔断的时候用
在这里插入图片描述

七.sentinel的线程隔离

一.配置隔离规则

feign客户端簇点链路这里配置规则
在这里插入图片描述
给 order-service服务中的UserClient的查询用户接口设置流控规则,线程数不能超过 2
在这里插入图片描述

二.JMeter测试

0秒内发送10个请求
在这里插入图片描述

结果

在这里插入图片描述

八.熔断降级测试

一.慢调用

慢调用:业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。

一.设置休眠时间

当order服务调用这个queryById,查询id=1的用户线程会休眠60ms
在这里插入图片描述

二.设置熔断规则

给 UserClient的查询用户接口设置降级规则,慢调用的RT阈值为50ms,统计时间为1秒,最小请求数量为5,失败阈值比例为0.4,熔断时长为5
在这里插入图片描述

三.浏览器测试

1秒内有5*0.4=2个请求超过60ms,会触发降级。在浏览器快速刷新5次,发现:
在这里插入图片描述
前几次user是不为null的,后面触发了熔断的满调用策略,对查询用户资源进行了熔断降级,访问id=102也降级了
在这里插入图片描述

二.异常比例、异常数

异常比例或异常数:统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断。

一.设置异常

当order服务调用这个queryById,查询id=2的用户,抛异常
在这里插入图片描述

二.设置熔断规则

给 UserClient的查询用户接口设置降级规则,统计时间为1秒,最小请求数量为5,失败阈值比例为0.4,熔断时长为5s
在这里插入图片描述
在5次请求中,只要异常比例超过0.4,也就是有2次以上的异常,就会触发熔断。

三.浏览器测试

在浏览器快速刷新5次,发现:
在这里插入图片描述

九.授权规则

一.基本规则

授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式:

  • 白名单:来源(origin)在白名单内的调用者允许访问

  • 黑名单:来源(origin)在黑名单内的调用者不允许访问

  • 资源名:就是受保护的资源,例如/order/{orderId}

  • 流控应用:是来源者的名单,

    • 如果是勾选白名单,则名单中的来源被许可访问。
    • 如果是勾选黑名单,则名单中的来源被禁止访问。
      在这里插入图片描述
      允许请求从gateway到order-service,不允许浏览器访问order-service,那么白名单中就要填写网关的来源名称(origin)

二.获取origin

Sentinel是通过RequestOriginParser这个接口的parseOrigin来获取请求的来源的。
order-service服务中,我们定义一个RequestOriginParser的实现类:
在这里插入图片描述
这个方法的作用就是从request对象中,获取请求者的origin值并返回。

默认情况下,sentinel不管请求者从哪里来,返回值永远是default,也就是说一切请求的来源都被认为是一样的值default。

三.给网关添加请求头

既然获取请求origin的方式是从reques-header中获取origin值,我们必须让所有从gateway路由到微服务的请求都带上origin头

修改gateway服务中的application.yml,添加一个defaultFilter:

spring:
  cloud:
    gateway:
      default-filters:
        - AddRequestHeader=origin,gateway

从gateway路由的所有请求都会带上origin头,值为gateway。而从其它地方到达微服务的请求则没有这个头。

四.配置授权规则

在这里插入图片描述

五.测试

1.跳过网关,访问order-service服务:
在这里插入图片描述
2.通过网关访问,因为在网关加了权限校验,所以得在url加上authorization=admin:
在这里插入图片描述

十.自定义异常结果

默认情况下,发生限流、降级、授权拦截时,都会抛出异常到调用方。异常结果都是flow limmiting(限流)。这样不够友好,无法得知是限流还是降级还是授权拦截。
在这里插入图片描述
BlockException包含多个不同的子类:

异常说明
FlowException限流异常
ParamFlowException热点参数限流的异常
DegradeException降级异常
AuthorityException授权规则异常
SystemBlockException系统规则异常

十一.规则持久化

一.规则管理模式

规则是否能持久化,取决于规则管理模式,sentinel支持三种规则管理模式:

  • 原始模式:Sentinel的默认模式,将规则保存在内存,重启服务会丢失。

  • pull模式:控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则。
    在这里插入图片描述

  • push模式:控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新。
    在这里插入图片描述
    码农不常用具体配置,不解说

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愛沢かりん

感谢您对我的支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值