• 07_sentinel—QPS—流控规则


    sentinel—QPS—流控规则

    流控规则

    应用场景:秒杀 大促 下单 订单回流处理

    在这里插入图片描述

    QPS(query per second) 每秒请求数,就是说服务器在一秒的时间内处理了多少个请求

    controller再加个请求

    @RequestMapping("flow")
    public String flow(){
        return  "正常访问";
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    这是如果你快速访问 http://localhost:8861/order/flow 就会显示

    Blocked by Sentinel (flow limiting)
    
    • 1

    自定义流控信息

    @RequestMapping("flow")
    @SentinelResource(value = "flow",blockHandler = "flowBlockHandler")
    public String flow(){
        return  "正常访问";
    }
    public String flowBlockHandler(BlockException e){
        return  "流控";
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    重启后 规则就没了 得重新设置 后续设置持久化

    在这里插入图片描述

    sentinel—并发线程数—流控规则

    并发线程数用于保护业务线程池不被慢调用耗尽

    Sentinel并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目(正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号呈隔离。并发数控制通常在调用端进行配置。

    controller层添加代码

    @RequestMapping("flowThread")
    @SentinelResource(value = "flowThread",blockHandler = "flowBlockHandler")
    public String flowThread() throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
        return  "正常访问";
    }
    
    //上面先新添加的  下面是原来的 为了直观我就放上来了
    
    
    public String flowBlockHandler(BlockException e){
        return  "流控";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    控制台设置

    在这里插入图片描述

    两个浏览器访问 http://localhost:8861/order/flowThread

    出现结果 一个再访问 另一个就会被流控的现象
    在这里插入图片描述

    sentinel—BlockException统一异常处理

    不想老是用@SentinelResource 来处理异常的话,可以定义一个BlockException统一异常处理,每一个方法的异常处理结果一样就适用,每一个方法的异常处理结果不想一样就不适用

    1.加统一返回结果类 Result

    package com.tian.order.domain;
    
    public class Result<T> {
        private Integer code;
        private String msg;
        private T data;
    
        public Result(Integer code, String msg, T data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
    
        public Result(Integer code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    
        public static Result error(Integer code, String msg){
            return new Result(code,msg);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    2.加统一处理类MyBlockExceptionHandler

    package com.tian.order.exception;
    
    import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
    import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
    import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
    import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
    import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.tian.order.domain.Result;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.MediaType;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @Component
    public class MyBlockExceptionHandler implements BlockExceptionHandler {
        Logger log= LoggerFactory.getLogger(this.getClass());
        public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception {
            //e.getRule() 资源 规则的信息信息
            log.info("BlockExceptionHandler BlockException============="+e.getRule());
            Result r=null;
            if(e instanceof FlowException){
                //流控
                r=Result.error(100,"接口限流了");
            }else if(e instanceof DegradeException){ //降级
                r=Result.error(101,"服务降级了");
            }
            else if(e instanceof ParamFlowException){
                r=Result.error(102,"热点参数限流了");
            }
            else if(e instanceof SystemBlockException){
                r=Result.error(103,"触发系统保护规则了");
            }
            else if(e instanceof AuthorityException){
                r=Result.error(104,"授权规则不通过");
            }
    
            //返回json数据
            response.setStatus(500);
            response.setCharacterEncoding("utf-8");
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            new ObjectMapper().writeValue(response.getWriter(),r);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    3.注释掉@SentinelResource

      @RequestMapping("flow")
        //@SentinelResource(value = "flow",blockHandler = "flowBlockHandler")
        public String flow(){
            return  "正常访问";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.控制台添加流控规则

    5.访问 http://localhost:8861/order/flow

    快速访问页面出现 {"code":100,"msg":"接口限流了","data":null}

    sentinel—关联流控模式

    在这里插入图片描述

    应用场景

    对数据库又增 又查的 那么就对增(插入)增加这个规则,让查询被流控

    例 生成订单访问量大的话就让查询订单限流

    controller层 代码

       @RequestMapping("/add")
        public String add(){
            System.out.println("下单成功!");
            return "生成订单";
        }
    
        @RequestMapping("/get")
        public String get(){
            return "查询订单";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    控制台增加规则

    在这里插入图片描述

    访问 http://localhost:8861/order/add (1s中3次以上)

    再访问 http://localhost:8861/order/get 出现限流

    sentinel—链路流控模式

               getUser
                /   \
               /     \
       /order/test1  /order/test2 
    
    • 1
    • 2
    • 3
    • 4

    上图中来自入口/order/test1和/order/test2的请求都调用到了资源getUser,Sentinel允许只根据某个入口的统计信息对资源限流

    1.service层

    public interface IOrderService {
        String getUser();
    }
    
    • 1
    • 2
    • 3
    @Service
    public class OrderServiceImpl implements IOrderService{
        //使用了@SentinelResource,就不会被全局统一异常处理了
        @SentinelResource(value = "getUser",blockHandler = "blockHandlerGetUser")
        public String getUser() {
            return "查询用户";
        }
    
        public String blockHandlerGetUser(BlockException e) {
            return "流控用户";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.controller层

        @Autowired
        IOrderService orderService;
    
        @RequestMapping("/test1")
        public String test1(){
            return orderService.getUser();
        }
    
        @RequestMapping("/test2")
        public String test2(){
            return orderService.getUser();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.控制台配置规则

    在这里插入图片描述

    访问 http://localhost:8861/order/test1 和 http://localhost:8861/order/test2

    发现链路模式不生效,配置文件添加

    spring.cloud.sentinel.web-contenxt-unity:false # 默认将调用链收敛
    
    • 1

    重启访问 发现/order/test1随便快速点击访问都可以,但/order/test2会被流控

    sentinel—流控效果介绍

    在这里插入图片描述

    sentinel—预热流控效果

    • 对激增流量的处理
    比如秒杀活动,一下子很多流量访问一个资源 ,这个时候就可以用预热流控,
    效果是 先让一部分人进来,经过缓存(例如redis),如果没有就去数据库,
    然后数据库再把值缓存到redis中,那后面慢慢进来的就会去redis层查,没有的去数据库查,数据库再慢慢补全查询记录到redis。
    
    • 1
    • 2
    • 3

    冷加载因子: codeFactor默认是3,即请求QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的QPS 阈值。

    在这里插入图片描述

    访问 http://localhost:8861/order/flow 快速点击 发现刚开始没几下就限流了,后面快速点击几十下都不限流

    sentinel—排队等待

    • 对脉冲流量的处理

    1s10个请求 4个线程

    快速失败结果

    在这里插入图片描述

    设置为排队等待 先让多的请求等待5s,等在空闲的时间再执行这些请求,超过时间则不执行

    在这里插入图片描述

    排队等待结果 (完全利用了空闲时间)

    在这里插入图片描述

    sentinel—熔断降级规则

    • 慢调用比例

    测试代码

    @RequestMapping("flowThread")
    //@SentinelResource(value = "flowThread",blockHandler = "flowBlockHandler")
    public String flowThread() throws InterruptedException {
        TimeUnit.SECONDS.sleep(2);
        return  "正常访问";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    启动 控制台配置规则

    在这里插入图片描述

    • 异常比例
    @RequestMapping("/err")
    public String err(){
        int i=1/0;
        return "hello";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    启动 控制台配置规则

    在这里插入图片描述

    • 异常数

    在这里插入图片描述

    sentinel—整合openfeign降级

    • 搭建环境

    order-openfeign-sentinel模块

    1.依赖

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
    
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    dependency>
    
    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-openfeignartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.service层 StockFeignService

    @FeignClient(value = "stock-nacos",path = "/stock")
    public interface StockFeignService {
    		
        //和stock-nacos模块中的一个方法一样
        @RequestMapping("/reduct")
        public String reduct2();
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.controller层

    @RestController
    @RequestMapping("/order")
    public class OrderController {
        @Autowired
        StockFeignService stockFeignService;
    
        @RequestMapping("/add")
        public String add(){
            System.out.println("下单成功!");
            String msg = stockFeignService.reduct2();
            return "hello feign"+msg;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.配置文件

    server:
      port: 8041
    #应用名称 nacos会将该名称当作服务名称
    spring:
      application:
        name: product-service
      cloud:
        nacos:
          server-addr: 127.0.0.1:8848
          discovery:
            username: nacos
            password: nacos
            namespace: public
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5.主启动类

    @SpringBootApplication
    @EnableFeignClients
    public class OrderNacosApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderNacosApplication.class,args);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    stock-nacos模块

    controller层

    @RequestMapping("/stock")
    public class StockController {
    
    @RequestMapping("/reduct2")
        public String reduct2(){
            int i=1/0;
            System.out.println("扣减库存");
            return "扣减库存"+port;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    访问测试 http://localhost:8041/order/add 页面报500

    整合sentinel

    order-openfeign-sentinel模块

    1.导入依赖

    
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.编写配置文件

    feign:
      sentinel:
        # openfeign整合sentinel
        enabled: true  #默认是false
    
    • 1
    • 2
    • 3
    • 4

    3.编写降级方法 StockFeignServiceFallback

    @Component
    public class StockFeignServiceFallback implements StockFeignService{
        public String reduct2() {
            return "降级啦!!!";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.StockFeignService接口调用

    @FeignClient(value = "stock-nacos",path = "/stock",fallback = StockFeignServiceFallback.class)
    public interface StockFeignService {
    
        @RequestMapping("/reduct")
        public String reduct2();
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.访问测试 http://localhost:8041/order/add 页面显示 hello feign降级啦!!!

    sentinel—热点参数流控

    1.controller添加代码

    /**
         * 热点规则,必须使用@SentinelResource
         * @param id
         * @return
         */
    @RequestMapping("/get/{id}")
    @SentinelResource(value = "getById",blockHandler = "HotBlockHander")
    public String getById(@PathVariable Integer id){
        System.out.println("正常访问");
        return "正常访问";
    }
    
    public String HotBlockHander(@PathVariable Integer id,BlockException e){
        return "热点异常处理";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.控制台配置规则

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    3.测试访问

    现象 http://localhost:8861/order/get/2 无论你请求多快都可以访问
    http://localhost:8861/order/get/1 请求快了页面就显示 热点异常处理

    sentinel—系统保护规则

    在这里插入图片描述

    在这里插入图片描述

    • CPU usage (1.5.0+版本)︰当系统CPU使用率超过阈值即触发系统保护(取值范围0.0-1.0),比较灵敏。
    • 平均RT: 当单台机器上所有入口流量的平均RT达到阈值即触发系统保护,单位是毫秒。
    • 并发线程数: 当单台机器上所有入口流呈的并发线程数达到阈值即触发系统保护。
    • 入口QPS: 当单台机器上所有入口流量的QPS达到阈值即触发系统保护。

    sentinel—规则持久化

    • 原始模式

    好处 无依赖

    坏处 应用重启规则就会消失,仅用于简单测试,不能用于生产环境

    • 拉模式
    • 推模式 (建议!!!)

    1.配置规则

    在这里插入图片描述

    在这里插入图片描述

    [{
        "resource": "/order/flow",
        "controlBehavior": 0,
        "count":2,
        "grade":1,
        "limitApp":"default",
        "strategy":0
    }]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    order-sentinel项目添加依赖

    <dependency>
        <groupId>com.alibaba.cspgroupId>
        <artifactId>sentinel-datasource-nacosartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    编写配置

    server:
      port: 8861
    spring:
      application:
        name: order-sentinel
      cloud:
        sentinel:
          transport:
            dashboard: 127.0.0.1:8888
          web-context-unify: false   # 默认将调用链收敛
          datasource:
            flow-rule:
              nacos:
                server-addr: 127.0.0.1:8848
                username: nacos
                password: nacos
                dataId: order-sentinel-flow-rule
                rule-type: flow
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    访问 http://localhost:8861/order/flow 已经有流控规则了,只要你刷新快就会被流控

    在这里插入图片描述

  • 相关阅读:
    C语言打印九九乘法表
    2.4、编码与调制
    优先队列题目:数组的最小偏移量
    【华为OD题库-008】座位调整-Java
    【王道数据结构】第三章 栈和队列
    Java从入门到精通-类和对象(一)
    C语言典范编程
    Moonbeam Ignite强势回归
    电力电子的一些知识
    JavaScript 变量提升的作用
  • 原文地址:https://blog.csdn.net/xixihaha_coder/article/details/126701087