《springcloud alibaba》 三 sentinel流量控制

发布于:2024-03-05 ⋅ 阅读:(67) ⋅ 点赞:(0)


在这里插入图片描述

sentinel官方中文文档

sentinel准备

sentinel控制台1.8.0

  • 注意需要跟springboot cloud版本与之对应,不然会有很多问题
    在这里插入图片描述

在这里插入图片描述
输入命令

java -jar sentinel-dashboard-1.8.0.jar
  • 注意默认端口是8080,很容易冲突
    在这里插入图片描述
  • 账号和密码都是sentinel
    在这里插入图片描述

流控规则 qps

创建一个maven模块,父类的包,可以查看第一篇文章

pom.xml

<?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">
    <parent>
        <artifactId>springcloudalibaba</artifactId>
        <groupId>com.cxy.springcloud</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cxy.ssentinelnew</groupId>
    <artifactId>sentinel-demo</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--sentinel启动器-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
    </dependencies>
</project>

  • 导入sentinel启动包

apllication.yml

server:
  port: 8010

spring:
  application:
    name: sentinel-demo
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080

  • dashboard 是sentinel地址
  • 记得启动sentinel控制台界面

启动类

package com.cxy.sentinel;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author wu
 * @version 1.0
 * @date 2024/2/26 15:52
 */
@SpringBootApplication
public class StartApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }
}

controller

package com.cxy.sentinel.controller;

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

/**
 * @author wu
 * @version 1.0
 * @date 2024/2/2 11:39
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    @RequestMapping("/add")
    public String add(){
        System.out.println("下单成功");
        return "Hello Feign!";
    }
}

查看结果

在这里插入图片描述

  • 红色是项目里面的服务名
  • 注意:需要访问接口后,再来查看,不然会显示空白,先访问下面接口
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 表示1秒钟之内超过2次就会流控
    在这里插入图片描述

流控提示不太友好

我们来修改一下代码

     @RequestMapping("/add")
    @SentinelResource(value = "add",blockHandler = "addBlockHandler")
    public String add(){
        System.out.println("下单成功");
        return "Hello Feign!";
    }

    public String addBlockHandler(BlockException exception){
        return "流控";
    }
  • addBlockHandler这个方法,有几点需要注意
    1. 一定是public
  • 2、返回值一定跟需要做流控的那个方法一样
  • 3、BlockException 的包记得,一定是sentinel下面的
    启动后,去访问http://localhost:8010/order/add接口,发现之前做的1秒2次流控不生效
    why?
    这是因为之前的规则是保存在内存中,重启服务器后, 就不存在,需要重新加一次
    在这里插入图片描述
    再来访问一下http://localhost:8010/order/add
    在这里插入图片描述
    -返回状态码也变成200,实际使用过程中,返回值,我们肯定会封装成一个返回类包装一下的

流控规则 线程数

package com.cxy.sentinel.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * @author wu
 * @version 1.0
 * @date 2024/2/2 11:39
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    /**
     * 流控----qps
     * @return
     */
    @RequestMapping("/add")
    @SentinelResource(value = "add",blockHandler = "addBlockHandler")
    public String add(){
        System.out.println("下单成功");
        return "Hello Feign!";
    }

    public String addBlockHandler(BlockException exception){
        return "流控";
    }

    /**
     *  流控--线程控制方法
     * @return
     * @throws InterruptedException
     */
    @RequestMapping("/addThread")
    @SentinelResource(value = "addThread",blockHandler = "addBlockHandler")
    public String addThread() throws InterruptedException {
        System.out.println("下单成功");
        TimeUnit.SECONDS.sleep(5);
        return "Hello Feign!"+Thread.currentThread().getName();
    }
}
  • addThread 这个方法是新增加的,其他的代码,跟qps的代码一样
  • 增加一个延迟,是为了测试方便测试线程数
    在这里插入图片描述
    在这里插入图片描述
    启动两个浏览器,才能测出线程数流控的效果
    在这里插入图片描述
  • 搞不清楚为什么,同一个浏览器,我看了一下线程名称也不一样,为什么不走流控

全局异常处理

在这里插入图片描述
在之前写的代码中,会存在一个问题,每一个需要流控、降级处理的方法,都需要加上@sentinelResource注解,在家一个异常处理的方式,用起来什么不方便,看起来也十分的别扭。
那有全局处理sentinel异常的方案,有的

pom.xml

<?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">
    <parent>
        <artifactId>springcloudalibaba</artifactId>
        <groupId>com.cxy.springcloud</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cxy.ssentinelnew</groupId>
    <artifactId>sentinel-demo</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--sentinel启动器-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
    </dependencies>
</project>

application.yml

server:
  port: 8010

spring:
  application:
    name: sentinel-demo
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080

启动类

package com.cxy.sentinel;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author wu
 * @version 1.0
 * @date 2024/2/26 15:52
 */
@SpringBootApplication
public class StartApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }
}

实体类

package com.cxy.sentinel.entity;

public enum ResponseCode {
    SUCCESS(200, "success"),
    FAILURE(201, "failure"),
    EXCEPTION(500, "exception"),
    INVALID_TOKEN(501, "invalidToken");

    private int code;
    private String message;

    ResponseCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage(){
        return message;
    }
}


package com.cxy.sentinel.entity;

import lombok.Data;

import java.io.Serializable;

@Data
public class ResponseResult<T> implements Serializable {
    private static final long serialVersionUID = 1L;

    private int code;

    private String message;

    private T payload;

    public ResponseResult() {
        this.code = ResponseCode.SUCCESS.getCode();
        this.message = ResponseCode.SUCCESS.getMessage();
    }

    public ResponseResult(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public ResponseResult(int code, String message, T payload) {
        this.code = code;
        this.message = message;
        this.payload = payload;
    }

    public static <T> ResponseResult<T> SUCCESS() {
        return new ResponseResult<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMessage(), null);
    }

    public static <T> ResponseResult<T> SUCCESS(T payload) {
        return new ResponseResult<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMessage(), payload);
    }

    public static <T> ResponseResult<T> FAILURE(String message) {
        return new ResponseResult<>(ResponseCode.FAILURE.getCode(), message);
    }

    public static <T> ResponseResult<T> EXCEPTION(String message) {
        return new ResponseResult<>(ResponseCode.EXCEPTION.getCode(), message, null);
    }

    public static <T> ResponseResult<T> EXCEPTION(ResponseCode resCode) {
        ResponseResult<T> resResult = new ResponseResult<>();
        resResult.setCode(resCode.getCode());
        resResult.setMessage(resCode.getMessage());
        return resResult;
    }

    public static <T> ResponseResult<T> INVALID_TOKEN(String message) {
        return new ResponseResult<>(ResponseCode.INVALID_TOKEN.getCode(), message);
    }
}


  • 返回辅助类

controller类

package com.cxy.sentinel.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.cxy.sentinel.entity.ResponseResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * @author wu
 * @version 1.0
 * @date 2024/2/2 11:39
 */
@RestController
@RequestMapping("/order")
public class OrderController {


    /**
     *  流控--异常处理
     * @return
     * @throws InterruptedException
     */
    @RequestMapping("/addException")
    public ResponseResult addException() throws InterruptedException {
        System.out.println("流控异常处理!");
        return ResponseResult.SUCCESS();
    }
}

异常类

package com.cxy.sentinel.config;

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.cxy.sentinel.entity.ResponseResult;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component  //  注册为Bean  让Spring管理
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        String msg = "未知异常";
        int status = 429;

// 通过判断异常的类型 来判断到底是限流还是熔断降级还是授权限制
        if (e instanceof FlowException) {
            msg = "请求被限流了";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级了";
        } else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            status = 401;
        }

        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.setStatus(status);
        new ObjectMapper().writeValue(response.getWriter(), ResponseResult.EXCEPTION(msg));
    }
}

  • 试过用全局注解的方式来处理sentinel的异常,不知道为什么捕获不到,有知道的朋友可以解答一下,网上我看也有类似的方法,但是,测试过不行

测试

先访问http://localhost:8010/order/addException接口,再增加一条流控为1的规则,表示1秒钟之内只能访问一次
在这里插入图片描述

  • 出现这个,表示设置成功

关联流控模式

在这里插入图片描述
流控模式,分为三种,直接、关联、链路

关联

类似场景,12306,如果下单人数过多,点击查询票的时候,就显示服务正在繁忙

当两个资源存在争取时,就会存在关联,例如,数据库的某个表的读写,写多,读少等等

    /**
     * 关联流控模式
     * @return
     */
    @RequestMapping("/addOrder")
    public String addOrder(){
        System.out.println("下单成功");
        return "生成订单!";
    }

    /**
     * 关联流控模式
     * @return
     */
    @RequestMapping("/get")
    public String get(){
        System.out.println("查询订单");
        return "查询订单!";
    }
  • 在全局异常处理的controller类中,增加如上代码
    在这里插入图片描述
    启动项目,增加流控,点击关联,访问http://localhost:8010/order/get 查询接口时,关联下单接口,意思是,下单接口访问过多时,查询会流控
    在这里插入图片描述
    为了方便测试,需要借助一个工具jmeter用来模拟发送请求

jmeter

jmeter测试工具
在这里插入图片描述

  • 表示100秒内,300个线程,1秒至少3次
    访问http://localhost:8010/order/get接口
    在这里插入图片描述

链路

跟全局异常处理一样的代码,增加如下代码

service

package com.cxy.sentinel.service;

/**
 * @author wu
 * @version 1.0
 * @date 2024/2/28 14:26
 */
public interface OrderService {
    /**
     * 查询用户
     * @return
     */
    public String getUser();
}


package com.cxy.sentinel.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;

/**
 * @author wu
 * @version 1.0
 * @date 2024/2/28 14:27
 */
@Service
public class OrderServiceImpl implements OrderService{
    @Override
    @SentinelResource(value = "getUser")
    public String getUser() {
        return "查询用户";
    }
}

  • 增加SentinelResource注解,说明是sentinel资源,在界面就可以进行设置

controller

在这里插入图片描述
-以前的controller增加如下代码

  @Autowired
    private OrderService orderService;

    //关联流控 访问/add 触发/get
    @RequestMapping("/test1")
    public String test1(){
        return orderService.getUser();
    }

    //关联流控 访问/add 触发/get
    @RequestMapping("/test2")
    public String test2(){
        return orderService.getUser();
    }

访问http://localhost:8010/order/test2,设置流控
在这里插入图片描述
继续访问http://localhost:8010/order/test2,三次,出现如下画面,说明,流控成功
在这里插入图片描述
== 为什么报错?==
这是因为service类里面增加@SentinelResource后,会导致,对应的接口,不走全局异常,只能自定义异常来处理

代码调整

在这里插入图片描述

  • 配置里面需要调整一下这个

package com.cxy.sentinel.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;

/**
 * @author wu
 * @version 1.0
 * @date 2024/2/28 14:27
 */
@Service
public class OrderServiceImpl implements OrderService{
    @Override
    @SentinelResource(value = "getUser",blockHandler="getUserHandler")
    public String getUser() {
        return "查询用户";
    }

    public String getUserHandler(BlockException ex) {
        return "流控用户";
    }
}


访问http://localhost:8010/order/test2,如下图,说明配置成功
在这里插入图片描述
总结起来:
两个坑点:

  • 配置里面application.yml配置里面需要设置成false, 全局流控异常处理不生效,需要自定义异常处理

流控效果

在这里插入图片描述

  • 流控效果分为三种

Warm UP

有一个预热的过程,长期处在一个低流量过程,突然一下子流量狂飙,很容易导致系统出问题,所以,通过冷启动,让通过的流量,缓慢的增加,在一定时间内,加到对应的阈值

在这里插入图片描述
设置快速失败为5

在这里插入图片描述

  • 设置1秒10次,循环4次
    在这里插入图片描述
  • 定时休息5秒
    在这里插入图片描述
  • 设置http请求
    在这里插入图片描述
    -通过上图可以发现,蓝色的线和绿色的线有重合的地方,我们的目标就是让蓝色的线,变平缓
    在这里插入图片描述
  • 设置成排队等待5秒,效果如下图
    在这里插入图片描述
  • 标红的地方,有空闲,说明,我们之前在线程哪里设置的,1秒10次,对服务器的压力不大

熔断降级规则

说到熔断,降级,我想大部分的人,脑海中,顿时就飘过hystrix,今天主要是看看sentinel的熔断

慢调用比例

在这里插入图片描述

  • 访问/order/addThread资源时,如果在1000毫秒内,请求数量超过5,并且这些数量中超过1000毫秒的请求数量的比例超过0.1则熔断1秒

代码和前面一样,在之前的基础上,增加
在这里插入图片描述

  /**
     *  熔断降级规则,----慢调用比例
     * @return
     * @throws InterruptedException
     */
    @RequestMapping("/addLevel")
    public String addLevel() throws InterruptedException {
        System.out.println("下单成功");
        TimeUnit.SECONDS.sleep(2);
        return "Hello Feign!"+Thread.currentThread().getName();
    }

三部曲:
1、访问接口http://localhost:8010/order/addLevel
2、添加熔断规则
在这里插入图片描述
3、jemter压测
在这里插入图片描述
在这里插入图片描述
再去访问,接口被熔断了
在这里插入图片描述

  • 熔断后,只有有一次不是慢查询,就会恢复正常

异常比例

熔断策略异常比例是以请求异常数量的比例作为阈值,当单位统计时长(statIntervalMs)内请求数大于设置的最小请求数,并且异常请求数的比例大于比例阈值,则接下来的请求会自动熔断,熔断时间为设置的熔断时长。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若在HALF-OPEN状态下有一个请求正常响应 则结束熔断,否则继续熔断。
在这里插入图片描述
先访问http://localhost:8010/order/err
在这里插入图片描述
在这里插入图片描述

  • 从第六次开始,就熔断降级

异常数

在这里插入图片描述
在这里插入图片描述

  • 连续访问3次后,服务就进行了熔断,会熔断10s

整合openFeign

openFeign代码
在这个基础上做测试
在这里插入图片描述

  • 主要是涉及两个项目

stock项目

在这里插入图片描述

    /**
     * 增加异常
     * @return
     */
    @RequestMapping("/reduct1")
    public String reduct1(){
       int a = 1/0;
        System.out.println("扣减库存!");
        return "扣减库存"+port;
    }

order项目

在这里插入图片描述

    /**
     * 产生异常
     * @return
     */
    @RequestMapping("/reduct1")
    public String reduct1(){
        String msg = stockFeignService.reduct1();
        return "Hello Feign!"+msg;
    }

在这里插入图片描述

pom.xml

<?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">
    <parent>
        <artifactId>springcloudalibaba</artifactId>
        <groupId>com.cxy.springcloud</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--Nacos做配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--添加openfeign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <!--sentinel启动器-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
    </dependencies>

</project>

  • 添加sentinel依赖

application.yml

在这里插入图片描述

  • 红色部分,是新增代码
server:
  port: 8015

spring:
  application:
    name: order-service
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      discovery:
        name: nacos
        password: nacos
        namespace: public

    loadbalancer:
      ribbon:
        enabled: false
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
      web-context-unify: false   #默认将调用链路收起来




####设置springboot级别
logging:
  level:
    com.cxy.order.feign.StockFeignService: debug
feign:
  client:
    config:
      stock-servic: ###对应微服务
        ###链接超时时间  默认2s
        connectTimeout: 5000
        ### 请求处理超时时间 默认5s
        readTimeout: 10000
  ##添加feign对sentinel的兼容
  sentinel:
    enabled: true

访问http://localhost:8015/order/reduct1,直接报错,有点不友好
在这里插入图片描述

openFeign降级报错友好处理

1、增加openFeign对sentinel的兼容
在这里插入图片描述

application.yml

feign:
  client:
    config:
      stock-servic: ###对应微服务
        ###链接超时时间  默认2s
        connectTimeout: 5000
        ### 请求处理超时时间 默认5s
        readTimeout: 10000
  ##添加feign对sentinel的兼容
  sentinel:
    enabled: true

增加异常处理类

package com.cxy.order.feign;

import org.springframework.stereotype.Component;

/**
 * @author wu
 * @version 1.0
 * @date 2024/2/21 17:54
 */
@Component
public class StockFeignServiceFallback implements StockFeignService{

    @Override
    public String reduct() {
        return "降级";
    }

    @Override
    public String reduct1() {
        return "降级";
    }
}

  • 返回异常处理提示

openFeign消费者接口改造

在这里插入图片描述

  • 跟以前的hystric一样的写法
    启动order项目,再来访问
    在这里插入图片描述
    到这里,openFeign降级就完成咯。

热点参数流控

热点即经常访问的数据,很多时候,我们需要针对一些频率很高的数据,对其使用限制。

代码

  /**
     * 热点规则,必须使用@SentinelResource
     *
     * @return
     */
    @RequestMapping("/get/{id}")
    @SentinelResource(value = "getById", blockHandler = "HotBlockHandler")
    public String getById(@PathVariable("id") Integer id) {
        System.out.println("正常访问:" + id);
        return "正常访问:" + id;
    }

    public String HotBlockHandler(@PathVariable("id") Integer id, BlockException e) {
        return "热点异常处理" + id;
    }
  • 还是在之前项目中,进行更改(Order项目)
    在这里插入图片描述
  • 单机阈值遵循一个原则,热点参数和普通参数,谁多,谁就是设置成单机阈值
    例如: 某个商品平台,今天晚上进行白酒秒杀,其他的商品没有活动,就可以把普通商品设置成单机阈值,白酒作为参数特殊设置。
  • 上面的效果,就是普通的商品,能1秒访问10次,商品id为1的,1秒钟只能访问2次。

直接访问http://localhost:8015/order/get/1 三次
在这里插入图片描述

系统保护规则

系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、线程数、入口 QPS 和CPU使用率监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

cpu

在这里插入图片描述

  • sentinel刚开始整的那个项目代码里面进行测试
package com.cxy.sentinel.config;

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.cxy.sentinel.entity.ResponseResult;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component  //  注册为Bean  让Spring管理
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        String msg = "未知异常";
        int status = 429;

// 通过判断异常的类型 来判断到底是限流还是熔断降级还是授权限制
        if (e instanceof FlowException) {
            msg = "请求被限流了";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级了";
        }else if (e instanceof SystemBlockException){
            msg = "系统规则保护";
        }    else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            status = 401;
        }

        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.setStatus(status);
        new ObjectMapper().writeValue(response.getWriter(), ResponseResult.EXCEPTION(msg));
    }
}

  • 之前的历史代码,少了一个SystemBlockException异常else判断的代码,这里补一下

在这里插入图片描述

  • 为了方便测试,cpu使用率的值是0-1,所以这里的0.01表示,只要cpu超过1,就会走系统保护

在这里插入图片描述

qps

在这里插入图片描述
这里的1,表示所有接口的平均qps,而不是某个接口的阈值

规则持久化

在这里插入图片描述

原始模式

存在内存中,开发环境测试使用,服务一重启,配置就消失

拉模式

pull模式的数据源(如本地文件、RDBMS等)一般是可写入的。使用时需要在客户端注册数据源:将对应的读数据源注册至对应的 RuleManager,将写数据源注册至transport的WritableDataSourceRegistry中。

推模式

生产环境下一般更常用的是push模式的数据源。对于push模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不应由Sentinel客户端进行,而应该经控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。因此推送规则正确做法应该是配置中心控制台/Sentinel控制台 → 配置中心 → Sentinel数据源 → Sentinel,而不是经Sentinel数据源推送至配置中心。这样的流程就非常清晰了:

nacos设置

在这里插入图片描述

  • 先新增nacos对应的配置

pom.xml

<?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">
    <parent>
        <artifactId>springcloudalibaba</artifactId>
        <groupId>com.cxy.springcloud</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--Nacos做配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--添加openfeign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <!--sentinel启动器-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <!--sentinel配置中心控制台推送-->
        <!--以nacos作为sentinel数据源的依赖-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
    </dependencies>

</project>

在这里插入图片描述

  • 在以前的基础上,新增了该接口

application.yml

server:
  port: 8015

spring:
  application:
    name: order-service
  cloud:
#    nacos:
#      server-addr: 127.0.0.1:8848
#      discovery:
#        name: nacos
#        password: nacos
#        namespace: public

    loadbalancer:
      ribbon:
        enabled: false
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
      web-context-unify: false   #默认将调用链路收起来
      datasource:
        flow-ds:
          nacos:
            server-addr: 127.0.0.1:8848
            username: nacos
            password: nacos
            namespace: public
            dataId: ${spring.application.name}-flow
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow




####设置springboot级别
logging:
  level:
    com.cxy.order.feign.StockFeignService: debug
feign:
  client:
    config:
      stock-servic: ###对应微服务
        ###链接超时时间  默认2s
        connectTimeout: 5000
        ### 请求处理超时时间 默认5s
        readTimeout: 10000
  ##添加feign对sentinel的兼容
  sentinel:
    enabled: true

  • flow-ds 是随便写的,其他的有讲究
    支持很多的数据库,这里我们使用的nacos,所以用nacos的配置
    ctrl+shift+\ 输入DataSourcePropertiesConfiguration,找到nacois得代码,打开
    在这里插入图片描述
    在这里插入图片描述
  • 可以进行参考配置

有个问题:不知道为什么,需要先调用一次服务的接口后,才能看到,我们之前在nacos里面的配置,同步到sentinel中,怀疑是不是缓存
在这里插入图片描述
到这里我们就实现sentinel配置持久化了
存在几个问题:
1.在nacos配置很复杂
2、在sentinel中变更后,怎么同步到nacos里面来,有知道朋友,可以留言评论

sentinel同步配置持续化到nacos

之前是只能通过在nacos里面设置json格式的方式来设置

sentinel同步到nacos演示

在sentinel里面,新增一条流控规则
在这里插入图片描述

  • 之前测试的时候,忘记截图,通过编辑来截图
    在这里插入图片描述
    在这里插入图片描述

源码

sentinel 控制台
下载zip包,引入idea
在这里插入图片描述

  • 主要是改造dashboard项目

修改pom.xml

在这里插入图片描述

  • 不然,会有一个service的类报错,注意jdk是8,如果版本不一样,得特殊处理

nacos包移动

在这里插入图片描述

  • 使用的nacos就移动nacos,到src下,跟当前目录一下的包下

application.properties

在这里插入图片描述

  • 增加一个配置
    在这里插入图片描述
    -找到nacosConfig,调整一下对应的代码, 如果有设置账号和密码,这里就需要调整一下,不知道的可以百度一下

配置

在这里插入图片描述
-NacosConfigUtil类的这两个配置也是有讲究的,不修改,默认分组是service_group

  • 第二个参数,意思就是生成文件的名称后缀
    在这里插入图片描述

修改代码

流控

流控需要注意:得区分是V1还是V2的接口,修改对应的代码
在这里插入图片描述

  • 新增流控就知道是走V1还是V2的结果咯
添加流控规则时同步推送到nacos

在这里插入图片描述
在这里插入图片描述

    @Autowired
    @Qualifier("flowRuleNacosProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("flowRuleNacosPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

  try {
            rulePublisher.publish(app,rules);
        }catch (Exception e){
            logger.info("同步失败");
        }
  • 按截图,添加对应的代码
测试

添加流控规则
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 设置的阈值是111,count也是111,说明sentinel的修改会同步到nacos
  • 注意: 上面我只设置了流控的

其他规则

参考这个博客设置

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到