Spring Cloud Alibaba Sentinel 简单使用

news2024/11/18 15:49:31

Sentinel

  • Sentinel 主要功能
  • Sentinel 作用
  • 常见的流量控制算法
    • 计数器算法
    • 漏桶算法
  • 令牌桶算法
  • Sentinel 流量控制
  • Sentinel 熔断
  • Sentinel 基本使用
    • 添加依赖
    • 定义资源
    • 定义限流规则
    • 定义熔断规则
    • 如何判断熔断还是限流
    • 自定义 Sentinel 异常
      • 局部自定义异常
      • 全局自定义异常
      • 系统自定义异常
    • 使用 Nacos 存储配置
      • 引入依赖
      • 设置配置文件
      • Nacos 中设置配置信息

Sentinel 主要功能

  1. 流量控制: 可以通过配置规则对接口的访问进行限制, 避免因流量过高而导致的系统崩溃.
  2. 服务熔断: 当后端服务不可用或异常时, 可以通过配置熔断规则快速失败并返回错误信息, 避免连锁故障.
  3. 系统负载保护: 根据系统负载情况, 自动控制流量的通过, 防止系统出现过载.
  4. 统计和监控: 提供实时的流量控制和熔断信息统计

Sentinel 作用

  1. 防止雪崩效应: 当访问发生异常时 Sentinel 可以通过熔断机制返回错误信息, 从而防止其他服务也出现故障.
  2. 流量控制: Sentinel 可以通过限流机制, 限制并发请求数量, 来防止突然出现大量请求导致系统过载.
  3. 保护系统稳定性: Sentinel 可以对请求进行限流和熔断, 避免某个服务发生故障从而导致系统不可用.

常见的流量控制算法

计数器算法

计数器算法是在一定时间内记录请求次数, 当超过规定时间后计数器就会清零然后重新开始计算, 当请求超过间隔时间内最大次数时就会拒绝访问
计数器算法的特点是: 实现简单, 但是存在"突刺现象"

漏桶算法

漏桶算法工作原理类似于一个底部有小孔的桶, 无论流入多少水, 流出的速度始终保持恒定. 当桶满时, 新的水会溢出, 即超出的流量被丢弃, 这种算法能够平滑突发流量, 常用于限制数据的传输速度
漏桶算法提供了一种机制, 可以让突发流量被整形, 以便为系统提供稳定的请求. 如: Sentinel 中流量整形(匀速排队功能)
image.png

令牌桶算法

令牌桶算法中, 存在一个固定大小的令牌桶, 该桶会以恒定的速率源源不断地产生令牌, 当系统需要发送数据时, 会从令牌桶中取出一个令牌, 如果桶中没有可用的令牌, 那么该次数据发送就会被限制, 这种机制确保了即使面临突发流量, 系统也能保持稳定运行
image.png
令牌桶算法和漏桶算法的区别是: 漏桶算法是匀速的处理请求, 而令牌桶算法可以应对突发的流量.

Sentinel 流量控制

image.png
流量控制的三种效果:

  1. 快速失败: 当请求触发限流规则后, 会被理解拒绝并抛出 FlowException. 这种方法适用于对系统处理能力确切已知的情况.
  2. 排队等待(匀速通过): 排队等待会控制请求的间隔时间, 让请求稳定并且匀速通过. 这种方法可以用来处理间隔性突发的高流量.
  3. 冷启动(Warm Up): 该方法是通过让流量缓慢增加, 在一定时间内逐渐增加到阈值上限, 从而防止流量突然增加时, 直接把系统拉升到高水位可能瞬间把系统压垮.

Sentinel 熔断

image.png
熔断策略也是三种:

  1. 慢调用比例: 在统计时长内, 如果时间超过最大RT则为慢请求, 如果慢请求超过阈值, 并且请求数量大于最小请求数, 就会触发熔断
  2. 异常比例: 在统计时长内, 如果请求的比例大于阈值, 并且请求数大于最小请求数, 就会触发熔断
  3. 异常数: 在统计时长内, 如果异常数大于阈值, 并且请求数大于最小请求数, 就会触发熔断

Sentinel 基本使用

添加依赖

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

定义资源

定义资源可通过代码或者注解实现
通过代码方式定义资源:

@RequestMapping("/getid")
public String getId() {
    try(Entry entry = SphU.entry("getid")) { // 定义资源
        return "getId: " + new Random().nextInt(100);
    }catch (BlockException e) {
        // 当前资源已经被限流或熔断
        return "被限制";
    }
}

通过注解方式定义资源:

@SentinelResource(value = "getname", blockHandler = "myBlockHandler")
    @RequestMapping("/getname")
    public String getName() throws InterruptedException {
        Thread.sleep(100);
        return "getName: " + new Random().nextInt(100);
    }

    /**
     * 限流之后的执行方法
     * @param blockException
     * @return
     */
    public String myBlockHandler(BlockException blockException) {
        if (blockException instanceof FlowException) {
            return "限流";
        } else if (blockException instanceof DegradeException) {
            return "熔断";
        }
        return "被限制";
    }

注意:

  1. myBlockHandler 的返回类型和参数必须和绑定的方法一致, 否则就会报错
  2. myBlockHandler 必须包含 BlockException 参数

@SentinelResource 属性说明

  • value: 资源名称(必填)
  • entryType: 资源调用的流量类型 EntryType.IN/EntryType.OUT(默认)
  • blockHandler: 限流或熔断执行时对应的方法
  • fallback/fallbackClass: 非 BlockException 时, 其他非限流/熔断是异常对应的方法
  • exceptionsToIgnore: 用于指定哪些异常被排除掉, 不好计入异常统计和 fallback 逻辑中

定义限流规则

    private static void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("getname"); // 必须, 资源名
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 必须, 限流指标 QPS/线程数
        rule.setCount(1); // 必须, 限流数量: 上一步线程数或QPS值
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

定义熔断规则

    private static void initDegradeRules() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource("getname"); // 资源名
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); // 熔断策略
        rule.setCount(10); // RT值
        rule.setStatIntervalMs(1000); // 统计时长
        rule.setSlowRatioThreshold(0.5); // 阈值
        rule.setMinRequestAmount(1); // 最小请求数
        rule.setTimeWindow(5); // 熔断时长 单位为秒
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);

    }

如何判断熔断还是限流

if (blockException instanceof FlowException) {
    return "限流";
} else if (blockException instanceof DegradeException) {
    return "熔断";
}

自定义 Sentinel 异常

Sentinel 异常分为三种: 局部自定义异常, 全局自定义异常, 系统自定义异常

局部自定义异常

    @SentinelResource(value = "getname", blockHandler = "myBlockHandler")
    @RequestMapping("/getname")
    public String getName() throws InterruptedException {
        Thread.sleep(100);
        return "getName: " + new Random().nextInt(100);
    }

    /**
     * 限流之后的执行方法
     * @param blockException
     * @return
     */
    public String myBlockHandler(BlockException blockException) {
        if (blockException instanceof FlowException) {
            return "限流";
        } else if (blockException instanceof DegradeException) {
            return "熔断";
        }
        return "被限制";
    }

局部自定义异常只需要创建一个方法然后在@SentinelResource 中设置即可

全局自定义异常

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 jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

/**
 * 定义 Sentinel 全局自定义异常
 */
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        int code = HttpStatus.TOO_MANY_REQUESTS.value();
        String msg = "未知异常";
        if (e instanceof FlowException) {
            msg = "被限流";
        } else if (e instanceof DegradeException) {
            msg = "被熔断";
        } else if (e instanceof ParamFlowException) {
            msg = "请求触发了热点限流";
        } else if (e instanceof AuthorityException) {
            code = HttpStatus.UNAUTHORIZED.value();
            msg = "暂无权限";
        }
        httpServletResponse.setContentType("application/json;charset=utf-8");
        httpServletResponse.setStatus(code);
        httpServletResponse.getWriter().println("{\"code\":" + code + ", \"msg\":\"" + msg +"\"}");
    }
}

全局自定义异常需要实现 BlockExceptionHandler 接口然后重写 handle 方法

系统自定义异常

如果只配置熔断和限流的情况下配置全局自定义异常即可, 但是配置一些特殊的规则如: 热点规则, 全局自定义异常就不会起作用, 就需要配置系统自定义异常

import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Objects;

/**
 * 自定义系统异常
 */
@RestControllerAdvice
public class SystemException {
    @ExceptionHandler(ParamFlowException.class)
    public HashMap<String, Object> ParamFlowException(ParamFlowException e) {
        return new HashMap<>(){{
            put("code", HttpStatus.TOO_MANY_REQUESTS.value());
            put("msg", "热点限流");
        }};
    }
}

使用 Nacos 存储配置

Sentinel 配置的规则默认存储到内存中, 会随着项目的重启而清空, 所以就需要对这些规则进行持久化配置

引入依赖

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

设置配置文件

spring:
  application:
    name: sentinel-demo
  cloud:
    sentinel:
      transport:
        dashboard: localhost:18080
      datasource:
        ds:
          nacos:
            server-addr: localhost:8848
            username: nacos
            password: nacos
            data-id: ${spring.application.name}-flow-rules
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: flow
        ds2:
          nacos:
            server-addr: localhost:8848
            username: nacos
            password: nacos
            data-id: ${spring.application.name}-degrade-demo
            group-id: DEFAULT_GROUP
            data-type: json
            rule-type: degrade

image.png

Nacos 中设置配置信息

限流:

[
  {
    "resource":"/user/getname",
    "limitApp":"default",
    "grade":1,
    "count":2,
    "strategy":0,
    "controlBehavior":0,
    "clusterMode":false

  },
  {
    "resource":"/user/getid",
    "limitApp":"default",
    "grade":1,
    "count":2,
    "strategy":0,
    "controlBehavior":0,
    "clusterMode":false

  }
]

image.png
熔断:

[{
    "resource":"/user/getname",
    "grade":0,
    "count":10,
    "timeWindow":5,
    "minRequestAmount":1,
    "statIntervalMs":1000,
    "slowRationThreshold":0.5
}]

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1234896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

战备器材管理系统-部队物资仓库管理系统

一、项目背景 传统的战备物资管理&#xff0c;一般依赖于一个非自动化的、以纸张文件为基础的系统来记录、追踪进出的货物&#xff0c;完全由人工实施仓库内部的管理&#xff0c;因此仓库管理的效率极其低下。对此&#xff0c;我们运用无线射频技术(RFID)的仓库智能管理系统&am…

RabbitMQ 基础操作

概念 从计算机术语层面来说&#xff0c;RabbitMQ 模型更像是一种交换机模型。 Queue 队列 Queue&#xff1a;队列&#xff0c;是RabbitMQ 的内部对象&#xff0c;用于存储消息。 RabbitMQ 中消息只能存储在队列中&#xff0c;这一点和Kafka相反。Kafka将消息存储在topic&am…

在无回显的情况下如何判断是否存在命令注入漏洞

在无回显的情况下如何判断是否存在命令注入漏洞 这种情况下可以使用OOB带外来实现&#xff0c;言而简之&#xff0c;就是利用命令执行漏洞去解析我们的dns如果dns日志有记录那就说明存在命令注入漏洞 首先先简单搭建一个无回显的命令注入 <?phpexec($_REQUEST[777]); ?&…

shell脚本判断语句

目录 一. 判断语句 1. 判断文件是否存在 test 2. 数值比较 3. 字符串比较 4. 逻辑运算 5. [ ] 与 [ [ ] ] 6. ( ) 与 { } 7. if 语句 二. 脚本应用 一. 判断语句 1. 判断文件是否存在 test 选项 -a 和 -e 都可以判断文件是否存在 只是 -a 选项在取反时有问题&#xf…

数字化转型导师坚鹏:数字化时代银行网点厅堂营销5大特点分析

数字化时代银行网点厅堂营销存在以下5大特点&#xff1a; 1、产品多样化&#xff1a;在数字化时代&#xff0c;银行的产品和服务变得更加多样化。除了传统的存款、贷款、理财等金融服务外&#xff0c;还新增了各种创新产品&#xff0c;如网上银行、移动支付、投资咨询、保险、…

5 个适用于 Linux 的开源日志监控和管理工具

当Linux等操作系统运行时&#xff0c;会发生许多事件和在后台运行的进程&#xff0c;以实现系统资源的高效可靠的使用。这些事件可能发生在系统软件中&#xff0c;例如 init 或 systemd 进程或用户应用程序&#xff0c;例如 Apache、MySQL、FTP 等。 为了了解系统和不同应用程序…

离线安装Linux包的方法

sklearn库安装方法&#xff08;有详细步骤流程&#xff09; 离线安装Linux包的方法——以sklearn为例 https://pypi.org/project/scikit-learn

百度搜索万亿规模特征计算系统实践

作者 | Jay 导读 本文主要介绍百度搜索在全网万亿级规模内容做内容理解的工程实践&#xff0c;涉及机器学习工程化、资源调度、存储优化等多个Topic。 全文6648字&#xff0c;预计阅读时间17分钟。 01 业务背景 百度收录了互联网海量内容&#xff0c;要索引这些内容&#xff0…

基于单片机预费电表控制系统(proteus仿真+源程序)

一、系统方案 1、本设计采用这51单片机作为主控器。 2、采集电量值送到液晶1602显示。 3、按键设置预设值&#xff0c;实际使用电量超过设置&#xff0c;蜂鸣器报警。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 void LCD_init(void) { …

#gStore-weekly | gBuilder功能详解之结构化数据抽取

上一个weekly中已经详细讲解了schema的设计&#xff0c;在schema设计好了之后&#xff0c;gBuilder支持将结构化和非结构化数据转化为RDF图数据。其中结构化数据支持数据的无损转化。 1. 技术介绍 gBuilder的结构化数据抽取采用D2RQ技术实现。 DR2Q是一个能够将关系数据库中…

Redis从入门到精通(二)- 入门篇

文章目录 0. 前言1. 入门篇[【入门篇】1.1 redis 基础数据类型详解和示例](https://icepip.blog.csdn.net/article/details/134438573)[【入门篇】1.2 Redis 客户端之 Jedis 详解和示例](https://icepip.blog.csdn.net/article/details/134440061)[【入门篇】1.3 redis客户端之…

KNN(k近邻法)算法理论和实战

KNN概念 k近邻法&#xff08;k-nearest neighbor&#xff0c;k-NN&#xff09;是一种基本分类与回归方法。 k近邻法的输入为实例的特征向量对应于特征空间的点&#xff1b;输出为实例的类别&#xff0c;可以取多类。 k近邻法假设给定一个训练数据集&#xff0c;其中的实例类…

基于非链式(数组)结点结构的二叉树的层序、先序、中序、后序输入创建以及层序、先序、中序、后序输出

这个系列来记录学习一下如何用数组完成二叉树的4种顺序的创建&#xff0c;以及其4种顺序的遍历。 我们知道&#xff0c;对于一棵二叉树而言它有4种遍历的顺序&#xff0c;那自然就导致其输入结点时&#xff0c;也分这四种顺序。 分别是—— 层序&#xff1a; …

Kotlin 核心语法,为什么选择Kotlin ?

Kotlin 是一个基于 JVM 的新的编程语言&#xff0c;由 JetBrains 开发。与Java相比&#xff0c;Kotlin的语法更简洁、更具表达性&#xff0c;而且提供了更多的特性。 Kotlin是使用Java开发者的思维被创建的&#xff0c;Intellij作为它主要的开发IDE。对于 Android开发者&#…

Java实现围棋算法

围棋是一种源自中国的棋类游戏&#xff0c;也是世界上最古老、最复杂的棋类游戏之一。该游戏由黑白两方交替放置棋子在棋盘上进行&#xff0c;目的是将自己的棋子占据更多的空间&#xff0c;并将对手的棋子围死或吃掉&#xff0c;最终获得胜利。围棋不仅是一种游戏&#xff0c;…

以太网_寻址

【架构图】 【ipconfig/all】 MAC地址&#xff1a;作用于本地网络&#xff0c;数据包发送到本地交换机或路由器后经判断目的地址是本地网络地址会转发给当前MAC地址对应的网线端口。 IP地址&#xff1a;供路由器寻址&#xff0c;会跟子网掩码进行运算&#xff0c;属于同一网络…

两种Deformable Attention的区别

先分别写一下流程 Deformable DETR(2020)的Deformable Attention 解释&#xff1a; Deformable Attention如下图所示K3, M3K是指每个zq会和K个offset算attention&#xff0c;M是指M个head&#xff0c; z q z_q zq​有NHW个&#xff1a; 参考点&#xff1a;reference points&am…

golang学习笔记——接口和继承比较1

继承 Go 语言的设计之初&#xff0c;就不打算支持面向对象的编程特性&#xff0c;因此 Go 不支持面向对象的三大特性之一——继承。但是 Go 可以通过组合的思想去实现 “继承”。继承是面向对象的三大特性之一&#xff0c;继承是从已有的类中派生出新的类&#xff0c;新的类能…

股票自选(四)

4-自选 自选表功能&#xff0c;均需要使用 Token 令牌进行操作&#xff0c;目的是为了将数据隔离。 添加自选表的作用是进行推送&#xff0c; 将 自选表中的近十天的涨跌幅情况通过邮箱的方式推送给对应的用户。 一. 添加到自选表 接口描述: 接口地址:/StockApi/stockSele…

快速幂极简写法快速幂求逆元

快速幂原理介绍 快速幂模板 int qmi(int a, int k, int p) {int res 1;while (k) {//后面的a其实是底数与其指数的运算结果了&#xff0c;是不断迭代的//第一个a其实就是a的2的0次方if (k & 1) res (res * a) % p;a (a * a) % p;//注意&#xff0c;a是一个不断变化的过…