05.Sentinel实现对微服务接口保护

Sentinel概述

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护等多个维度来帮助您保障微服务的稳定性。

img

gitee:https://gitee.com/rmlb/Sentinel/

github: https://github.com/alibaba/Sentinel

Sentinel与Hystrix 区别

Sentinel 不支持线程池隔离? 改成 线程数隔离

线程池隔离 每个接口都有自己独立的线程池 相互之间没有任何影响的

但是 最终创建的 线程数 越来越多 会影响到服务器端cpu的资源 cpu飙高的问题。

Hystrix 支持 线程池隔离

\1. hystrix具有的功能

线程池隔离/信号量隔离 Sentinel 不支持线程池隔离;信号量隔离对应 Sentinel 中的线程数限流。

熔断器 Sentinel 支持按平均响应时间、异常比率、异常数来进行熔断降级。

Command 创建 直接使用 Sentinel SphU API 定义资源即可,资源定义与规则配置分离。

规则配置 在 Sentinel 中可通过 API 硬编码配置规则,也支持多种动态规则源

注解支持 Sentinel 也提供注解支持

开源框架支持 Sentinel 提供 Servlet、Dubbo、Spring Cloud、gRPC 的适配模块,开箱即用;若之前使用 Spring Cloud Netflix,可迁移至 Spring Cloud Alibaba

为什么Sentinel 不支持线程隔离,因为线程池隔离 每个业务接口单独自己独立的线程池,会引发

CPU飙高的问题。

功能Sentinel(阿里巴巴团队研发)Hystrixresilience4j
隔离策略信号量隔离(并发线程数限流)线程池隔离/信号量隔离信号量隔离
熔断降级策略基于响应时间、异常比率、异常数基于异常比率基于异常比率、响应时间
实时统计实现滑动窗口(LeapArray)滑动窗口(基于 RxJava)Ring Bit Buffer
动态规则配置支持多种数据源支持多种数据源有限支持
扩展性多个扩展点插件的形式接口的形式
基于注解的支持支持支持支持
限流基于 QPS,支持基于调用关系的限流有限的支持Rate Limiter
流量整形支持预热模式、匀速器模式、预热排队模式(流量规则处可配置)不支持简单的 Rate Limiter 模式
系统自适应保护支持不支持不支持
控制台提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等简单的监控查看不提供控制台,可对接其它监控系统

Sentinel环境搭建

Maven依赖

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

手动限流方式

qps限流

1.限制服务器 qps 当调用该api的QPS达到阈值的时候,进行限流;

当QPS超过阈值,会采取措施进行流控,策略包含:直接拒绝、Warm Up、匀速排队。

(1)直接拒绝:为默认的流控方式:直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT),拒绝后抛出FlowException。适用于系统处理能力已知(系统处理能力的水位已知)

(2)Warm Up方式,即预热/冷启动方式。通过冷启动,让通过的流量缓慢增加,逐渐增加到阈值上线(给系统一个预热时间),避免冷启动系统被压垮。

(3)匀速排队:让请求匀速通过,对应的是令牌桶算法(注意:匀速排队模式暂时不支持 QPS > 1000 的场景。)

 /**
     * 初始化限流路由策略
     *
     * @return
     */
    @RequestMapping("/initFlowQpsRule")
    public String initFlowQpsRule() {
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        // 创建限流资源
        rule1.setResource("getSentinelQps");
        // QPS控制在2以内
        rule1.setCount(2);
        // QPS限流
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        //限流应用default
        rule1.setLimitApp("default");
        //添加该限流规则
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
        return "....限流配置初始化成功..";
    }
 /**
     * 演示getSentinelQps QPS 对接口限流
     *
     * @return
     */
    @RequestMapping("/getSentinelQps")
    public String getSentinelQps() {
        Entry entry = null;
        try {
            entry = SphU.entry("getSentinelQps");
            // 执行我们服务需要保护的业务逻辑
            log.info("正常执行业务逻辑代码...");
            return "getSentinelQps";
        } catch (Exception e) {
            log.error("<e:{}>", e);
            return "该接口访问频率过多,请稍后重试!";
        } finally {
            // SphU.entry(xxx) 需要与 entry.exit() 成对出现,否则会导致调用链记录异常
            if (entry != null) {
                entry.exit();
            }
        }
    }

并发限流

限制服务器端同时处理线程数量 基于并发数限流 当调用该api的线程数达到阈值的时候,进行限流。

1.并发数控制用于保护业务线程池不被慢调用耗尽,可以采用线程池隔离的隔离方案(不同业务使用不同的线程池);

2.sentinel采用的方法是,统计当前请求上下文的线程数据(正在执行的调用数据),超出阈值就会拒绝新的请求,效果类似于“信号量”隔离(信号量适用于那些资源有明确访问数量限制的场景,常用于限流 )。

   /**
     * 初始化限流路由策略
     *
     * @return
     */
    @RequestMapping("/initFlowQpsRule2")
    public String initFlowQpsRule2() {
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        // 创建限流资源
        rule1.setResource("getSentinelThreads");
        // 线程数是为2
        rule1.setCount(2);
        // 线程数类型
        rule1.setGrade(RuleConstant.FLOW_GRADE_THREAD);
        //限流应用default
        rule1.setLimitApp("default");
        //添加该限流规则
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
        return "....限流配置初始化成功..";
    }
   /**
     * 演示getSentinelThreads  线程数限流
     *
     * @return
     */
    @RequestMapping("/getSentinelThreads")
    public String getSentinelThreads() {
        Entry entry = null;
        try {
            entry = SphU.entry("getSentinelThreads");
            // 执行我们服务需要保护的业务逻辑
            log.info("正常执行业务逻辑代码...");
            Thread.sleep(3000);
            return "getSentinelQps";
        } catch (Exception e) {
            log.error("<e:{}>", e);
            return "服务器端忙,请稍后重试!";
        } finally {
            // SphU.entry(xxx) 需要与 entry.exit() 成对出现,否则会导致调用链记录异常
            if (entry != null) {
                entry.exit();
            }
        }
    }

改造代码启动项目自动注册限流规则

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 自动加载限流规则
 */
@Component
@Slf4j
public class SentinelApplicationRunner implements ApplicationRunner {
    /**
     * 限流资源名称 getSentinelThreads
     */
    private static final String SENTINE_KEY_SENTINELTHREADS = "getSentinelThreads";
    /**
     * 限流资源名称 getSentinelQps
     */
    private static final String SENTINE_KEY_GETSENTINELQPS = "getSentinelQps";

    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<FlowRule> rules = new ArrayList<FlowRule>();
        // 新增限流规则1
        FlowRule rule1 = new FlowRule();
        rule1.setResource(SENTINE_KEY_SENTINELTHREADS);
        // QPS控制在2以内
        rule1.setCount(1);
        // QPS限流
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        rules.add(rule1);

        FlowRule rule2 = new FlowRule();
        // 创建限流资源
        rule2.setResource(SENTINE_KEY_GETSENTINELQPS);
        // QPS控制在2以内
        rule2.setCount(2);
        // QPS限流
        rule2.setGrade(RuleConstant.FLOW_GRADE_THREAD);
        //限流应用default
        rule2.setLimitApp("default");
        //添加该限流规则
        rules.add(rule2);
        FlowRuleManager.loadRules(rules);
        log.info(">>>限流服务接口配置加载成功>>>");
    }
}

注解形式配置管理Api限流

1.@SentinelResource value参数:流量规则资源名称、

2.blockHandler 限流/熔断出现异常执行的方法

3.fallback 服务的降级执行的方法

    /**
     * sentinelAnnotation 演示通过注解的方式 使用
     *
     * @return
     */
    @RequestMapping("sentinelAnnotationQps")
    @SentinelResource(value = "getSentinelQps", blockHandler = "getSentinelQpsException")
    public String sentinelAnnotationQps() {
        return "sentinelAnnotation";
    }

控制台形式管理流控规则

Sentinel 环境快速搭建

Sentinel-Dashboard

链接:http://note.youdao.com/noteshare?id=8b31a62bf9618288b215fee9e25bc875

下载对应Sentinel-Dashboard

https://github.com/alibaba/Sentinel/releases/tag/1.7.1 运行即可。

运行执行命令

java -Dserver.port=8718 -Dcsp.sentinel.dashboard.server=localhost:8718 -Dproject.name=sentinel-dashboard -Dcsp.sentinel.api.port=8719 -jar Sentinel的安装包

范例:

1.8718属于界面端口号

2.8719属于API通讯的端口号

http://127.0.0.1:8718/#/dashboard/home

登录成功之后 账户和密码是为:sentinel/sentinel

img

SpringBoot项目整合控制台

1.编写测试接口

  /**
     * 整合getSentinelDashboardQps 仪表盘
     *
     * @return
     */
    @SentinelResource(value = "getSentinelDashboardQps", blockHandler = "getSentinelDashboardQpsException")
    @RequestMapping("/getSentinelDashboardQps")
    public String getOrderDashboard() {
        return "getOrderDashboard";
    }

    /**
     * 被限流后返回的提示
     *
     * @param e
     * @return
     */
    public String getSentinelDashboardQpsException(BlockException e) {
        log.error("<e:{}>", e);
        return "该接口已经被限流啦!";
    }

2.配置文件中新增:

server:
  port: 22223
spring:
  application:
    name: mayikt-member
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        ## 将数据上报 sentinel transport 仪表盘
        dashboard: 127.0.0.1:8718
      eager: true

img

Sentinel流控规则

Sentinel 动态QPS限流

1.相关测试代码:

    /**
     * 整合getSentinelDashboardQps 仪表盘
     *
     * @return
     */
    @SentinelResource(value = "getSentinelDashboardQps", blockHandler = "getSentinelDashboardQpsException")
    @RequestMapping("/getSentinelDashboardQps")
    public String getSentinelDashboardQps() {
        return "getOrderDashboard";
    }

    /**
     * 整合getSentinelDashboardThreads 仪表盘
     *
     * @return
     */
    @SentinelResource(value = "getSentinelDashboardThreads", blockHandler = "getSentinelDashboardQpsException")
    @RequestMapping("/getSentinelDashboardThreads")
    public String getSentinelDashboardThreads() throws InterruptedException {
        log.info("<正在开始执行业务逻辑代码...>");
        Thread.sleep(3000);
        return "getSentinelDashboardThreads";
    }

    /**
     * 被限流后返回的提示
     *
     * @param e
     * @return
     */
    public String getSentinelDashboardQpsException(BlockException e) {
        log.error("<e:{}>", e);
        return "该接口已经被限流啦!";
    }

2.访问:http://127.0.0.1:8718/#/dashboard/flow/mayikt-member

编辑流控规则

img

1.资源名:唯一名称,默认是请求路径,。

2.针对来源:指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制。

3.阈值类型/单机阈值:QPS(每秒请求数量): 当调用该接口的QPS达到阈值的时候,进行限流 / 线程数:当调用4.该接口的线程数达到阈值的时候,进行限流 。

5.是否集群:是否集群配置

如果是基于QPS 底层是基于令牌桶算法

如果是基于线程数 底层是基于信号量算法

img

1.直接(默认):接口达到限流条件时,开启限流。

2.关联:当关联的资源达到限流条件时,开启限流 (适合做应用让步)。

3.链路:当从某个接口过来的资源达到限流条件时,开启限流。

使用动态新增流控规则

资源名称:

如果该接口上没有加上 @SentinelResource

默认的资源名称就是为 该接口访问地址 /sentinelTestQps

一定要加上/

Sentinel关联服务限流

当关联的资源达到限流条件时,开启限流 (适合做应用让步)。

例如资源A getSentinelDashboardQpsA的关联资源 getSentinelDashboardQpsB

getSentinelDashboardQpsB 如果达到阈值则会导致 资源A 被限流

img

注意:模拟的过程中,选择阈值类型是为:线程数

相关代码:

   /**
     * 整合getSentinelDashboardQps 仪表盘
     *
     * @return
     */
    @SentinelResource(value = "getSentinelDashboardQpsA", blockHandler = "getSentinelDashboardQpsException")
    @RequestMapping("/getSentinelDashboardQpsA")
    public String getSentinelDashboardQpsA() throws InterruptedException {
        log.info("<getSentinelDashboardQpsA>");
        Thread.sleep(3000);
        return "getSentinelDashboardQpsA";
    }

    /**
     * 整合getSentinelDashboardQps 仪表盘
     *
     * @return
     */
    @SentinelResource(value = "getSentinelDashboardQpsB", blockHandler = "getSentinelDashboardQpsException")
    @RequestMapping("/getSentinelDashboardQpsB")
    public String getSentinelDashboardQpsB() throws InterruptedException {
        log.info("<getSentinelDashboardQpsB>");
        Thread.sleep(3000);
        return "getSentinelDashboardQpsB";
    }

http://127.0.0.1:22223/getSentinelDashboardQpsA

http://127.0.0.1:22223/getSentinelDashboardQpsB

img

Sentinel链路限流

img

Sentinel 提供2个接口分为为:getSentinelA 、 getSentinelB

都在调用show 方法,但是只需要对getSentinelA调用show方法限流。

    @RequestMapping("/getSentinelA")
    public String getSentinelA() {
        sentinelManage.show();
        return "getSentinelA";
    }


    @RequestMapping("/getSentinelB")
    public String getSentinelB() {
        log.info("getSentinelB");
        sentinelManage.show();
        return "getSentinelB";
    }

http://127.0.0.1:22223/getSentinelA ----访问getSentinelA被限流

http://127.0.0.1:22223/getSentinelB ----没有被限流

Sentinel快速失败/排队等待

1.快速失败(默认): 直接失败,抛出异常,不做任何额外的处理,是最简单的效果

2.Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的1/3,然后慢慢增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。

3.排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。

img

Sentinel 设置黑名单和白名单

让你设计 根据黑名单和白名单 来对接口限制访问。

白名单 该ip可以访问到该接口的

黑名单该ip 是不可以访问到该接口

1.编辑授权规则 设置流控应用 黑名单:禁止127.0.0.1

img

2.代码中需要配置IpLimiter 根据用户在请求中头中的IP 设置黑名单和白名单

import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author 余胜军
 * @ClassName IpLimiter
 * @qq 644064779
 * @addres www.mayikt.com
 * 微信:yushengjun644
 */
@Component
public class IpLimiter implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        return httpServletRequest.getRemoteAddr();
    }
}

http://127.0.0.1:22223/login

img

注意事项

如果接口上没有加上 @SentinelResource 资源名称就是为接口名称

在控制台项目中新增限流规则 资源名称 注意是需要加上/

Sentinel 雪崩/熔断/降级概念

在微服务架构中,经常会出现一些名词 例如:服务雪崩、服务熔断、服务降级、服务隔离等概念。

服务雪崩

1.在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,但是由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务堆积,最终导致服务瘫痪。其实,在单体服务中,高并发也会导致服务瘫痪

2.在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。

3.于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩效应”

调用链中:大量的请求到服务A入口(上游服务), 服务A调用服务B 服务B调用服务C 如果服务B或者服务C 宕机了 中间会引发重试,重试过程中会产生大量请求堆积,线程资源一直被占用,最终导致整个链崩溃,这种现象称之为服务雪崩效应。

img

我们无法完全杜绝雪崩源头的发生,只有做好足够的容错,保证在一个服务发生问题,不会影响到其它服务的正常运行, 我们就需要对接口实现容错方案。

模拟雪崩

 /**
     * 演示服务雪崩效应
     *
     * @return
     */
    @RequestMapping("getMayiktA")
    public String getMayiktA() throws InterruptedException {
        // 模拟该接口处理需要5s
        log.info("...正在处理业务逻辑getMayiktA....");
        Thread.sleep(5000);
        return "mayikt";
    }

    /**
     * 另外接口
     *
     * @return
     */
    @RequestMapping("/getMayiktB")
    public String getMayiktB() {
        log.info("...正在处理业务逻辑getMayiktB....");
        return "mayiktB";
    }

服务器端配置线程数

server:
  port: 8090
  tomcat:
    max-threads: 30 ###最大线程数30

jmeter.bat 压力测试 http://127.0.0.1:8090/getMayiktA

导致 http://127.0.0.1:8090/getMayiktB 接口 服务器端没有足够线程执行, 浏览器一直转圈圈中…

img

服务容错

服务隔离

它是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其它模块,不影响整体的系统服务。常见的隔离方式有:线程池隔离(sentinel 是有)和信号量隔离(线程数)(模块隔离)

img

服务熔断

服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用。

服务降级

服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。

1.超时降级:主要配置好超时时间和超时重试次数和机制,并使用异步机制探测回复情况

2.失败次数降级:主要是一些不稳定的 api,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况

3.故障降级:比如要调用的远程服务挂掉了(网络故障、DNS故障、http服务返回错误的状态码、rpc服务抛出异常),则可以直接降级。

4.限流降级:秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)。

qps 3万 走服务降级 时间窗口 30s 无法访问该接口 直接返回一个友好提示

服务限流

对服务器接口实现限流 保护服务接口。 qps或者线程数限流。

Sentinel 服务降级

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。

Sentinel 提供以下几种熔断策略:

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

以上内容摘自与:github “Sentinel ” 中文文档。

blockHandler限流异常回调方法

fallback 服务降级回调的方法

例子:例如调用该接口 1s 调用5次 都是失败,触发 服务降级策略

该接口设定降级的时间10s 意味着该接口10s 内无法访问,直接走

fallback 服务降级回调的方法

RT(平均响应时间策略)

当1s 内持续进入 5 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。

img

访问rtDemo01接口1s 内5个请求 响应时间超过10毫秒,则会触发

服务降级策略 10s 该接口无法访问,走服务降级回调方法。

img

    /**
     * rtDemo01
     *
     * @return
     */
    @GetMapping("/rtDemo01")
    @SentinelResource(value = "rtDemo01", fallback = "rtDemo01Fallback")
    public String rtDemo01() throws InterruptedException {
        log.info("<rtDemo01>");
        Thread.sleep(20);
        return "rtDemo01";
    }

    /**
     * 服务降级回调方法
     *
     * @return
     */
    public String rtDemo01Fallback() {
        log.info("服务降级啦...");
        return "当前接口处理忙,请稍后重试!";
    }

通俗易懂:在1s内如果发送5个请求 平均响应时间都达到该阈值,则开启服务降级,在设定规定时间窗口内暂时无法访问到该接口,等时间该时间窗口结束之后就会关闭服务降级。

jmeter 压测 http://127.0.0.1:8090/rtDemo01

img

img

相关代码:

    /**
     * rtDemo01
     *
     * @return
     */
    @GetMapping("/rtDemo01")
    @SentinelResource(value = "rtDemo01", fallback = "rtDemo01Fallback")
    public String rtDemo01() throws InterruptedException {
        Thread.sleep(1000);
        return "rtDemo01";
    }

    /**
     * 服务降级回调方法
     *
     * @return
     */
    public String rtDemo01Fallback() {
        return "当前接口处理忙,请稍后重试!";
    }

img

异常比例

当资源的每秒请求量>= 5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

img1s 内 5次请求 全部都是报错,就触发服务降级 服务降级时间10s

走服务降级方法。

相关代码:

    /**
     * 异常比例
     *
     * @return
     */
    @RequestMapping("/getMayiktError")
    @SentinelResource(value = "getMayiktError", fallback = "getMayiktErrorFallback")
    public String getMayiktError(Integer age) {
        log.info("<getMayiktError>");
        Integer j = 1 / age;
        return "getMayiktError:" + j;
    }


    public String getMayiktErrorFallback(Integer age) {
        return "当前该接口错误次数太多,暂时无法访问!";
    }

img

压力测试:http://127.0.0.1:8090/getMayiktError?age=0

正常访问:

http://127.0.0.1:8090/getMayiktError?age=1

img

异常数

当资源近1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。

相关代码

    /**
     * 异常数
     *
     * @return
     */
    @RequestMapping("/getMayiktErrorCount")
    @SentinelResource(value = "getMayiktErrorCount", fallback = "getMayiktErrorCountFallback")
    public String getMayiktErrorCount(Integer age) {
        log.info("<getMayiktErrorCount>");
        Integer j = 1 / age;
        return "getMayiktErrorCount:" + j;
    }


    public String getMayiktErrorCountFallback(Integer age) {
        return "当前该接口错误次数太多,暂时无法访问!";
    }

img

Sentinel 热点规则

https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制

用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

相关代码:

    /**
     * 模拟秒杀接口
     *
     * @return
     */
    @RequestMapping("/seckill")
    @SentinelResource(value = "seckill", blockHandler = "seckillFallbackBlockHandler")
    public String seckill(Long userId) {
        log.info("<userId:{}>", userId);
        return "seckill:" + userId;
    }

    public String seckillFallbackBlockHandler(Long userId, BlockException exception) {
        log.info("<userId,{}您访问的频率太高,请稍后重试!>", userId);
        return "userId:" + userId + "您访问的频率太高,请稍后重试!";
    }

img

热点规例外限流:

img

Sentinel 整合Gateway

Gateway 配置整合Sentinel

img

从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId

自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

基于SpringBoot再构建一个service-gateway网关模块,使用时需引入以下模块(以 Maven 为例):

   <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>0.2.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>

    </dependencies>

增加配置

server:
  port: 81
####服务网关名称
spring:
  application:
    name: mayikt-gateway
  cloud:
    gateway:
      discovery:
        locator:
          ####开启以服务id去注册中心上获取转发地址
          enabled: true
          ###路由策略127.0.0.1:81/mayikt-member
      routes:
        ###路由id
        - id: mayikt-member
          #### 基于lb负载均衡形式转发
          uri: lb://mayikt-member
          filters:
            - StripPrefix=1
          ###匹配规则
          predicates:
            - Path=/mayikt-member/**
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        ## 将数据上报 sentinel transport 仪表盘
        dashboard: 127.0.0.1:8718
      eager: true
      #配置限流之后,响应内容
      scg:
        fallback:
          ## 两种模式,一种是response返回文字提示信息,
          ## 一种是redirect,重定向跳转,需要同时配置redirect(跳转的uri)
          mode: response
          ## 响应的状态
          response-status: 200
          ## 响应体
          response-body: '{"code": 200,"message": "请求失败,稍后重试!"}'

如果Sentinel 控制台 没有展示 API管理。

Gateway服务启动,设置该参数

@SpringBootApplication
public class AppGateway {
    public static void main(String[] args) {
        System.setProperty("csp.sentinel.app.type", "1");
        SpringApplication.run(AppGateway.class);
    }
}

让后重启Sentinel 控制器 刷新

img

Sentinel整合Gateway 限流规则

匹配模式根据前缀

img

img

tongg

访问网关接口测试

http://127.0.0.1:81/mayikt-member/member

频繁刷新访问

img

精确模式

/mayikt-member/member

img

img

访问接口:http://127.0.0.1:81/mayikt-member/getMayikt 没有被限流

访问接口:http://127.0.0.1:81/mayikt-member/member 被限流

img

通过网关访问接口,开头mayikt-member qps 1 ——

Sentinel 持久化

Sentinel 客户端如果重启之后 数据最终丢失 ,我们将Sentinel 持久化到

nacos、mysql等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值