1.7 Sentinel限流熔断应用实践

1.Sentinel简介

1.1背景分析

在我们日常生活中,经常会在淘宝、天猫、京东、拼多多等平台上参与商品的秒杀、抢购以及一些优惠活动,也会在节假日使用12306 手机APP抢火车票、高铁票,甚至有时候还要帮助同事、朋友为他们家小孩拉投票、刷票,这些场景都无一例外的会引起服务器流量的暴涨,导致网页无法显示、APP反应慢、功能无法正常运转,甚至会引起整个网站的崩溃。

我们如何在这些业务流量变化无常的情况下,保证各种业务安全运营,系统在任何情况下都不会崩溃呢?我们可以在系统负载过高时,采用限流、降级和熔断,三种措施来保护系统,由此一些流量控制中间件诞生。例如Sentinel。

1.2Sentinel概述

Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。
Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

Sentinel核心分为两个部分:

  • 核心库(Java 客户端):能够运行于所有 Java 运行时环境,同时对Dubbo /Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行。

1.3安装Sentinel服务

Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能,其控制台安装步骤如下:
第一步:打开sentinel下载网址https://github.com/alibaba/Sentinel/releases,因为目前国内访问国外网址比较困难,其jar包文件已上传到了项目工程中,也可以自行下载:
在这里插入图片描述

第二步:下载Jar包(可以存储到一个sentinel目录),如图所示:
在这里插入图片描述
第三步:在sentinel对应目录,打开命令行(cmd),启动运行sentinel

java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar

sentinel服务默认是8080端口,但是因为有很多服务都默认使用8080端口,为了避免端口占用问题,我们这里指定使用8180端口进行启动;并且我们后续指定了其控制台访问地址为localhost:8180;指定其名字为sentinel-dashboard,最后去执行jar包;

检测启动过程,如图所示:
在这里插入图片描述

1.4访问Sentinel服务

第一步:假如Sentinel启动ok,通过浏览器进行访问测试,如图所示:

在这里插入图片描述

第二步:登陆sentinel,默认用户和密码都是sentinel,登陆成功以后的界面如图所示:

在这里插入图片描述

2.Sentinel限流入门

2.1 概述

我们系统中的数据库连接池,线程池,nginx的瞬时并发等在使用时都会给定一个限定的值,这本身就是一种限流的设计。限流的目的防止恶意请求流量、恶意攻击,或者防止流量超过系统峰值。

2.2 准备工作

第一步:Sentinel 应用于服务提供方(sca-provider),在消费方添加依赖如下:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

此依赖添加后,会在我们项目中添加一个拦截器,这个拦截器会指定请求进行拦截,然后检测你的请求是否在限流范围之内,假如在这个范围之内就会对请求进行限流操作;

第二步:打开服务消费方配置文件bootstrap.yml,添加sentinel配置,代码如下:

spring:
  cloud:
    sentinel:
      transport:
         dashboard: localhost:8180 # 指定sentinel控制台地址。

第三步:创建一个用于演示限流操作的Controller对象,例如:

package com.jt.provider.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/provider")
public class ProviderSentinelController {
       @GetMapping("/sentinel01")
       public String doSentinel01(){
           return "sentinel 01 test  ...";
       }
}

第三步:启动sca-provider服务,然后对指定服务进行访问,如图所示:
在这里插入图片描述

第四步:刷新sentinel 控制台,实时监控信息,如图所示:
在这里插入图片描述
Sentinel的控制台其实就是一个SpringBoot编写的程序,我们需要将我们的服务注册到控制台上,即在微服务中指定控制台的地址,并且还要在消费端开启一个与sentinel控制台传递数据端的端口,控制台可以通过此端口调用微服务中的监控程序来获取各种信息。

2.3 Sentinel限流入门实践

我们设置一下指定接口的流控(流量控制),QPS(每秒请求次数)单机阈值为1,代表每秒请求不能超出1次,要不然就做限流处理,处理方式直接调用失败。

第一步:选择要限流的链路,如图所示:
在这里插入图片描述
第二步:设置限流策略,如图所示:
在这里插入图片描述
第三步:反复刷新访问消费端端服务,检测是否有限流信息输出,如图所示:
在这里插入图片描述

2.4 小节面试分析

  1. Sentinel是什么?
    • 阿里推出一个流量控制平台,流量防卫兵
  2. 类似Sentinel的产品你知道有什么?
    • hystrix早期第一代微服务产品
  3. Sentinel是如何对请求进行限流的?
    • 基于sentinel依赖提供的拦截器
  4. 你了解哪些限流算法?
    • 计数器、令牌桶、漏斗算法,滑动窗口算法等…
  5. Sentinel 默认的限流算法是什么?
    • 滑动窗口算法

3.Sentinel流控规则分析

3.1 阈值类型

  • QPS(Queries Per Second):当调用相关url对应的资源时,QPS达到单机阈值时,就会限流。
  • 线程数:当调用相关url对应的资源时,线程数达到单机阈值时,就会限流。

3.2 设置限流模式

Sentinel的流控模式代表流控的方式,默认直接限流模式,还有关联限流模式,链路限流模式。

3.2.1 直接模式

Sentinel默认的流控处理就是【直接->快速失败】。
在这里插入图片描述

3.2.2 关联模式

当关联的资源达到阈值,就限流自己。例如设置了关联资源为/ur2时,假如关联资源/url2的qps阀值超过1时,就限流/url1接口(是不是感觉很霸道,关联资源达到阀值,是本资源接口被限流了)。这种关联模式有什么应用场景呢?我们举个例子,订单服务中会有2个重要的接口,一个是读取订单信息接口,一个是写入订单信息接口。在高并发业务场景中,两个接口都会占用资源,如果读取接口访问过大,就会影响写入接口的性能。业务中如果我们希望写入订单比较重要,要优先考虑写入订单接口。那就可以利用关联模式;在关联资源上面设置写入接口,资源名设置读取接口就行了;这样就起到了优先写入,一旦写入请求多,就限制读的请求。例如

第一步:在ProviderSentinelController中添加一个方法,例如:

   @GetMapping("/sentinel02")
   public String doSentinel02(){
     return "sentinel 02 test  ...";
   }

第二步:在sentinel中做限流设计,例如
在这里插入图片描述

在这里插入图片描述

第三步:再次打开一个测试窗口,对/provider/sentinel02进行快速的多次访问后及时刷新/provider/sentinel01的状态,要注意测试时一定要手快,快速多次访问/provider/sentinel02服务后,立马刷新一次/provider/sentinel01服务,例如:

在这里插入图片描述

这种设计思路的目的就是在某一重要服务访问量急剧加大时,限流某些不重要的服务,留存服务器性能给其重要的服务使用,从而可以使其承担更多的访问并发量;

3.2.3 链路模式

链路模式只记录指定链路入口的流量。也就是当多个服务对指定资源调用时,假如流量超出了指定阈值,则进行限流。被调用的方法用@SentinelResource进行注解,然后分别用不同业务方法对此业务进行调用,假如A业务设置了链路模式的限流,在B业务中是不受影响的。现在对链路模式做一个实践,例如:

例如现在设计一个业务对象,代码如下(为了简单,可以直接写在启动类内部):

第一步:在指定包创建一个ResourceService类,代码如下:

package com.jt.provider.service;
@Service
public class ResourceService{
    @SentinelResource("doGetResource")
    public String doGetResource(){
        return "doGetResource";
    }
}

@SentinelResource注解描述的方法会在Sentinel控制台创建一个链路,还可以给其传参作为其链路的名字;

第二步:在ProviderSentinelController中添加一个方法,例如:

    @Autowired
    private ResourceService resourceService;
    @GetMapping("/sentinel03")
    public String doSentinel03() throws InterruptedException {
    	 //请求链路中的资源访问
        resourceService.doGetResource();
        return "sentinel 03 test";
    }

第三步:在sentinel中配置限流规则,例如:
在这里插入图片描述

在这里插入图片描述
设置链路流控规则后,再频繁对限流链路进行访问,检测是否会出现500异常,这个异常是因为doGetResource方法将限流报错抛出给controller但controller并未处理导致的,是正常的限流结果;例如

在这里插入图片描述
说明:链路限流返回的限流报错信息是抛出的异常信息,需要我们自定义返回的报错信息,不然会显示对用户极不友好的500报错;流控模式为链路模式时,假如是sentinel 1.7.2以后版本,Sentinel Web过滤器默认会聚合所有URL的入口为sentinel_spring_web_context,因此单独对指定链路限流会不生效,需要在bootstrap.yml添加如下语句来关闭URL PATH聚合,例如:

    sentinel:
      transport:
        dashboard: localhost:8180 # 指定sentinel控制台地址。
      web-context-unify: false

添加配置后,我们创建doSentinel04方法,并重启服务后,依次访问doSentinel03与doSentinel04服务,然后观察Sentinel控制台:

    @GetMapping("/sentinel03")
    public String doSentinel04() throws InterruptedException {
        //请求链路中的资源访问
        //resourceService.doGetResource();
        //return "sentinel 03 test";
        return resourceService.doGetResource();
    }

此时有俩个不同的doSentinel03与doSentinel04链路,并且链路指向同一个资源doGetResource,在实际应用中,我们就可以控制不同的链路进行限流,而不影响我们最终指向的资源;

在这里插入图片描述

还有,当我们也可以基于@SentinelResource注解描述的方法进行限流后的异常进行自定义处理,其步骤如下:

第一步:定义blockHandlerClass,例如:

package com.jt.provider.service;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class ResourceBlockHandler {
    /**
     * 注意此方法中的异常类型必须为BlockException (
     * 它是所有限流,降级等异常的父类类型),方法的返回
     * 值类型为@SentinelResource注解描述的返回值类型,
     * 方法的其他参数为@SentinelResource注解描述的方法参数,
     * 并且此方法必须为静态方法
     * @param ex
     * @return
     */
    public static String call(BlockException ex){
        log.error("block exception {}", ex.getMessage());
        return "访问太频繁了,稍等片刻再访问";
    }
}

第二步:修改ResourceService类中doGetResource方法上@SentinelResource注解中的属性定义,例如:

@SentinelResource(value="doGetResource",
        blockHandlerClass = ResourceBlockHandler.class,
        blockHandler = "call")
public String doGetResource(){
    return "do get resource";
}

@SentinelResource注解描述的方法会在sentinel控制台创建一个链路资源,这个链路的名称默认为value属性的值,当出现限流时,客户端默认看到的是一个500异常,假如希望对限流结果进行自定义的处理,可以考虑使用blockHandlerClass属性指定一个限流处理类,然后再通过blockHandler属性指定具体异常处理方法,这个异常处理方法必须与@SentinelResource注解描述的方法返回值类型相同,同时必须是静态的static方法,方法中的参数可以是BlockException类型;

第三步:在controller方法中,调用@Sentinel注解描述的方法,例如:

/**
 * 演示链路限流
 * @return
 */
    @Autowired
    private ResourceService resourceService;
    @GetMapping("/sentinel03")
    public String doSentinel03() throws InterruptedException {
        //请求链路中的资源访问
        //resourceService.doGetResource();
        //return "sentinel 03 test";
        return resourceService.doGetResource();
    }

此时我们再次设置链路限流规则,然后重复刷新访问,我们可以看到比较友好的限流提示了:
在这里插入图片描述

3.3 小节面试分析

  1. 你了解sentinel中的阈值应用类型吗?
    • 两种:QPS,线程数
  2. Sentinel的限流规则中默认有哪些限流模式?
    • 直连,关联,链路
  3. Sentinel的限流效果有哪些?
    • 快速失败:超过阈值直接失败
    • 预热:假设有600个请求,这600个请求在一定时间内(例如60秒内)逐步允许访问(每秒允许10个请求访问),而不是直接全部允许访问,就是预热
    • 排队:例如我们现在的设置是每秒允许请求访问一次,假设我们有100个请求,这100个请求不会报错,而是在一直等待,每秒只允许一个请求访问;

4.Sentinel降级应用实践

4.1 概述

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。

Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。

4.2 准备工作

在ProviderController 类中添加doSentinel05方法,基于此方法演示慢调用过程下的限流,代码如下:

    //AtomicLong 类支持线程安全的自增自减操作
    private AtomicLong atomicLong=new AtomicLong(1);
    @GetMapping("/sentinel05")
    public  String doSentinel05() throws InterruptedException {
        //获取自增对象的值,然后再加1
        long num=atomicLong.getAndIncrement();
        log.info("num=" +num);
        if(num%2==0){//模拟50%的慢调用比例
            Thread.sleep(200);
        }
        return "sentinel 05 test";
    }

说明,我们在此方法中通过计数的方式,在偶数次访问时设置休眠200毫秒,目的是为了演示慢调用(响应时间比较长).

4.3 Sentinel降级入门

接下来,我们基于一个请求链路,进行服务降级及应用实践,例如:
第一步:服务启动后,选择要降级的链路,如图所示:
在这里插入图片描述第二步:设置要降级的链路,如图所示:
在这里插入图片描述

这里表示熔断策略选择"慢调用比例",表示在统计时常1s内请求数超过3次时才进行统计,假如平均响应时间超过200毫秒的有30%,则对请求进行熔断,熔断时长为10秒钟,10秒以后恢复正常。

第三步:对指定链路进行刷新,多次访问测试,检测页面上是否会出现 Blocked By Sentinel (flow Limiting)内容.

我们也可以进行断点调试,在DefaultBlockExceptionHandler中的handle方法内部加断点,分析异常类型,假如异常类型DegradeException则为降级熔断。

4.4 Sentinel 异常处理

系统提供了默认的异常处理机制,假如默认处理机制不满足我们需求,我们可以自己进行定义。定义方式上可以直接或间接实现BlockExceptionHandler接口,并将对象交给spring管理。
在这里插入图片描述

package com.jt.provider.controller;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义限流,降级等异常处理对象
 */
@Slf4j
@Component
public class ServiceBlockExceptionHandler
     implements BlockExceptionHandler {
    /**
     * 用于处理BlockException类型以及子类类型异常
     */
    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       BlockException e) throws Exception {
        //设置响应数据编码
        response.setCharacterEncoding("utf-8");
        //告诉客户端响应数据的类型,以及客户端显示内容的编码
        response.setContentType("text/html;charset=utf-8");
        //向客户端响应一个json格式的字符串
        //String str="{\"status\":429,\"message\":\"访问太频繁了\"}";
        Map<String,Object> map=new HashMap<>();
        map.put("status", 429);
        map.put("message","访问太频繁了");
        String jsonStr=new ObjectMapper().writeValueAsString(map);
        PrintWriter out = response.getWriter();
        out.print(jsonStr);
        out.flush();
        out.close();
    }
}

此时我们再次模拟降级熔断,就可以看到我们自定义的异常处理提示了:
在这里插入图片描述

4.5 小节面试分析

  1. 何为降级熔断?
    • 让外部应用停止对服务的访问,生活中跳闸,路障设置-此路不通
  2. 为什么要进行熔断呢?
    • 平均响应速度越来越慢或经常出现异常,这样可能会导致调用链堆积,最终系统崩溃
  3. Sentinel中限流,降级的异常父类是谁?
    • BlockException
  4. Sentinel 出现降级熔断时,系统底层抛出的异常是谁?
    • DegradeException
  5. Sentinel中异常处理接口是谁?
    • BlockExceptionHandler
  6. Sentinel中异常处理接口下默认的实现类为?
    • DefaultBlockExceptionHandler
  7. 假如Sentinel中默认的异常处理规则不满足我们的需求怎么办?
    • 我们可以自己定义处理规则,实现BlockExceotionHandler接口即可;
  8. 我们如何自己定义Sentinel中异常处理呢?
    • 直接或间接实现BlockExceptionHandler
  9. Sentinel熔断降级策略有哪些?
    • 慢调用比例、异常比例、异常数

5.Sentinel热点规则分析(重点)

5.1 概述

何为热点?热点即经常访问的数据。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制。
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制。

热点参数限流会统计传入参数中的热点数据,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。其中,Sentinel会利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。

5.2 快速入门

第一步:在ProviderSentinelController中添加如下方法,例如:

        @GetMapping("/sentinel/findById")
        @SentinelResource("resource")
        public String doFindById(@RequestParam("id") Integer id){
            return "resource id is "+id;
        }

不添加@RequestParam注解传入的id可以为null,为了避免恶意攻击,所以我们需要添加这个注解; @SentinelResource注解表明当前方法使用热点参数限流规则进行控制;

第二步:服务启动后,选择要限流的热点链路,如图所示:
在这里插入图片描述
第三步:设置要限流的热点,如图所示:
在这里插入图片描述

热点规则的限流模式只有QPS模式(这才叫热点)。参数索引为@SentinelResource注解的方法参数下标,0代表第一个参数,1代表第二个参数。单机阈值以及统计窗口时长表示在此窗口时间超过阈值就限流。例如上面的设置表示第1个参数,2秒内有1次请求就进行限流;

第四步:多次访问热点参数方法,前端会出现如下界面,如图所示:
在这里插入图片描述
然后,在后台出现如下异常表示限流成功。

com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException: 10

其中,热点参数其实说白了就是特殊的流控,流控设置是针对整个请求的;但是热点参数他可以设置到具体哪个参数,甚至参数针对的值,这样更灵活的进行流控管理。
一般应用在某些特殊资源的特殊处理,如:某些商品流量大,其他商品流量很正常,就可以利用热点参数限流的方案。

5.3 特定参数设计

在热点限流界面的高级选项中,我们还可以针对参数类型,参数值,限流阈值等进行设定:
在这里插入图片描述

我们可以将参数设置为下图中的值,然后做测试:
在这里插入图片描述

当前参数设置的请求中,对于除888外的其他参数,1秒内最多访问3次,超过就会被限流;而特殊参数888在1秒内只能请求1次,超过1次就会被限流;

5.4 小节面试分析

  1. 如何理解热点数据?
    • 访问频度比较高的数据,某些商品、谋篇文章、某个视频
  2. 热点数据的限流规则是怎样的?
    • 主要是针对参数进行限流设计
  3. 热点数据中的特殊参数如何理解?
    • 热点限流中的某个参数值的阈值设计
  4. 对于热点数据的访问出现限流以后底层异常是什么?
    • ParamFlowException

6.Sentinel系统规则(了解)

6.1 概述

系统在生产环境运行过程中,我们经常需要监控服务器的状态,看服务器CPU、内存、IO等的使用率;主要目的就是保证服务器正常的运行,不能被某些应用搞崩溃了;而且在保证稳定的前提下,保持系统的最大吞吐量。

6.2 快速入门

Sentinel的系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load(负载)、RT(响应时间)、入口 QPS 、线程数和CPU使用率五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。如图所示:
在这里插入图片描述

在这里插入图片描述

系统规则是一种全局设计规则,其中:

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5
  • CPU使用率:当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

说明,系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务。

6.3 小节面试分析

  1. 如何理解sentinel中的系统规则?
    • 是对所有链路的控制规则,是一种系统保护策略
  2. Sentinel的常用系统规则有哪些?
    • RT,QPS,CPU,线程,Load-linux,unix
  3. Sentinel系统保护规则被触发以后底层会抛出什么异常?
    • SystemBlockException

7.Sentinel授权规则(重要)

7.1 概述

很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的黑白名单控制的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。例如微信中的黑名单。

7.2 快速入门

sentinel可以基于黑白名单方式进行授权规则设计,如图所示:
在这里插入图片描述
黑白名单规则(AuthorityRule)非常简单,主要有以下配置项:

  • 资源名:即限流规则的作用对象
  • 流控应用:对应的黑名单/白名单中设置的规则值,多个值用逗号隔开.
  • 授权类型:白名单,黑名单(不允许访问).

案例实现:

定义请求解析器,用于对请求进行解析,并返回解析结果,sentinel底层在拦截到用户请求以后,会对请求数据基于此对象进行解析,判定是否符合黑白名单规则,例如:

第一步:定义RequestOriginParser接口的实现类,在接口方法中解析请求参数数据并返回,底层会基于此返回值进行授权规则应用。

package com.jt.provider.controller;

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

import javax.servlet.http.HttpServletRequest;

@Component
public class DefaultRequestOriginParser implements RequestOriginParser {
	//http://localhost:8081/provider/sentinel01?origin=app1
    @Override
    public String parseOrigin(HttpServletRequest request) {
        String origin = request.getParameter("origin");//这里的参数名会与请求中的参数名一致
        return origin;
    }
}

我们这里主要是构建一个请求解析对象,可以对请求数据的报文进行解析,例如请求行,请求头,请求体等;

第二步:定义流控规则,如图所示:
在这里插入图片描述第三步:执行资源访问,检测授权规则应用,当我们配置的流控应用值为app1时,假如规则为黑名单,则基于http://ip:port/path?origin=app1的请求不可以通过,其请求处理流程如图下:
在这里插入图片描述

同样的,如果将其设置为白名单,则只有这俩个参数的可以访问,其他参数的均不可以访问;

7.3 尝试基于请求ip等方式进行黑白名单的规则设计

第一步: 修改请求解析器,获取请求ip并返回,例如:

package com.jt.provider.controller;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;

@Component
public class DefaultRequestOriginParser implements RequestOriginParser {
    //http://localhost:8081/provider/sentinel01?origin=app1
    @Override
    public String parseOrigin(HttpServletRequest request) {
        //String origin = request.getParameter("origin");//这里的参数名会与请求中的参数名一致
        //return origin;
        //获取访问请求中的ip地址,基于ip地址进行黑白名单设计(例如在流控应用栏写ip地址)
        String ip= request.getRemoteAddr();
        System.out.println("ip="+ip);
        return ip;
    }//授权规则中的黑白名单的值,来自此方法的返回值
}

第二步:在sentinel控制台定义授权规则,例如:
在这里插入图片描述
第三步:规则定义后以后,基于你的ip地址,进行访问测试,检测黑白名单效果.

7.4 自定义拦截器,实现基于时间实现访问控制

新建interceptor包,并创建TimeInterceptor类实现HandlerInterceptor接口,并重写preHandle方法:

package com.jt.provider.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalTime;


/**
 * 定义一个基于时间的控制拦截器
 * */
public class TimeInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取当前系统时间
        LocalTime nowTime = LocalTime.now();
        int hour = nowTime.getHour();
        if(hour<9 || hour>17){
            //false表示请求到此结果,true表示放行会去执行后面的拦截器或controller对象
            throw new RuntimeException("请在9点--17点之间进行访问!!");//return false;
        }
        return true;
    }
}

配置需要拦截的请求:

package com.jt.provider.interceptor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 设置需要拦截的请求
 * */
@Configuration
public class SpringWebController implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TimeInterceptor())
                .addPathPatterns("/provider/sentinel03");
    }
}

打开访问进行访问测试;

7.5 小节面试分析

  • 如何理解Sentinel中的授权规则?(对指定资源的访问给出的一种简易的授权策略)
  • Sentinel的授权规则是如何设计的?(白名单和黑名单)
  • 如何理解Sentinel中的白名单?(允许访问的资源名单)
  • 如何理解Sentinel中的黑名单?(不允许访问的资源名单)、
  • Sentinel如何识别白名单和黑名单?(在拦截器中通过调用RequestOriginParser对象的方法检测具体的规则)
  • 授权规则中RequestOriginParser类的做用是什么?(对流控应用值进行解析,检查服务访问时传入的值是否与
  • RequestOriginParser的parseOrigin方法返回值是否相同。)

8.总结(Summary)

总之,Sentinel可为秒杀、抢购、抢票、拉票等高并发应用,提供API接口层面的流量限制,让突然暴涨而来的流量用户访问受到统一的管控,使用合理的流量放行规则使得用户都能正常得到服务。

8.1 重难点分析

  1. Sentinel诞生的背景?
    • 计算机的数量是否有限,处理能力是否有限,并发比较大或突发流量比较大
  2. 服务中Sentinel环境的集成,初始化?
    • 添加依赖-两个,sentinel配置
  3. Sentinel 的限流规则?
    • 阈值类型-QPS&线程数,限流模式-直接,关联,链路
  4. Sentinel 的降级(熔断)策略?
    • 慢调用,异常比例,异常数
  5. Sentinel 的热点规则设计
    • 掌握热点规则设计
  6. Sentinel 系统规则设计?
    • 了解全局规则定义,针对所有请求有效
  7. Sentinel 授权规则设计?
    • 黑白名单

8.2 FAQ分析

  • 为什么要限流?
  • 你了解的那些限流框架?(sentinel)
  • 常用的限流算法有那些?(计数,令牌桶-电影票,漏桶-漏斗,滑动窗口)
  • Sentinel有哪些限流规则?(QPS,线程数)
  • Sentinel有哪些限流模式?(直接,关联-创建订单和查询订单,链路限流-北京六环外不限号,但是五环就限号)
  • Sentinel 的降级(熔断)策略有哪些?(慢调用-响应时长,异常比例-异常占比,异常数)
  • Sentinel 的热点规则中的热点数据?(热卖商品,微博大咖,新上映的电影)
  • 如何理解Sentinel 授权规则中的黑白名单?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值