Spring Cloud Alibaba Sentinel 简单使用

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.mfbz.cn/a/173012.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网工内推 | 字节原厂,正式编,网络工程师,最高30K*15薪

01 字节跳动 招聘岗位&#xff1a;网络虚拟化高级研发工程师 职责描述&#xff1a; 1、负责字节跳动虚拟网络产品的研发&#xff0c;包括但不局限于网络VPC、NAT、LB负载均衡等&#xff1b; 2、负责字节跳动网络基础平台的研发&#xff0c;包括但不局限于网络控制面系统、容器…

JS--localStorage设置过期时间的方案(有示例)

原文网址&#xff1a;JS--localStorage设置过期时间的方案(有示例)_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍如何使用localStorage设置数据的过期时间。 问题描述 localStorage是不支持设置过期时间的&#xff0c;cookie虽然支持设置过期时间但它存的数据量很小。所…

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客户端之…

打码平台之图鉴的使用步骤

打码平台之图鉴 背景&#xff1a; ​ 今天给大家推荐一个我一直使用的验证码识别平台&#xff0c;图鉴&#xff0c;我没有收费&#xff0c;我只是觉得这个网站使用方便&#xff0c;支持验证码种类多&#xff0c;好了&#xff0c;话不多说&#xff0c;上教程&#xff01; 注册…

小程序制作(超详解!!!)第十六节 小程序的基本架构

1.题目描述 创建一个包含:首页、教学、科研、资讯和关于我们5个标签的小程序&#xff0c;每个标签都有对应的页面、图标和标签文字&#xff0c;点击某个标签将切换到对应的页面&#xff0c;同时该标签的图标和文字颜色都会发生变化页面的标题也发生相应的变化&#xff0c;而其…

数字IC基础:有符号数和无符号数的加减运算

相关阅读 数字IC基础https://blog.csdn.net/weixin_45791458/category_12365795.html?spm1001.2014.3001.5482 首先说明&#xff0c;本篇文章并不涉及补码运算正确性的证明&#xff0c;仅是对补码运算在有符号数和无符号数中运行进行讨论。 补码运算最大的作用在于消除计算机…

RabbitMQ 基础操作

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

2023年【T电梯修理】考试题及T电梯修理考试报名

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 T电梯修理考试题是安全生产模拟考试一点通总题库中生成的一套T电梯修理考试报名&#xff0c;安全生产模拟考试一点通上T电梯修理作业手机同步练习。2023年【T电梯修理】考试题及T电梯修理考试报名 1、【多选题】GB/T1…

什么是PyQt?

什么是Qt? Qt是一个著名的跨平台C图形用户界面应用程序开发框架。它由Qt公司开发,于1995年首次发布。Qt支持各种桌面,嵌入式和移动平台。 Qt的特点包括: 跨平台支持:Qt应用程序可以编译到多种平台运行,包括Windows,Mac,Linux,Android,iOS等。这大大简化了跨平台应用程序的开…

2023年亚太杯数学建模思路 - 案例:最短时间生产计划安排

文章目录 0 赛题思路1 模型描述2 实例2.1 问题描述2.2 数学模型2.2.1 模型流程2.2.2 符号约定2.2.3 求解模型 2.3 相关代码2.4 模型求解结果 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 最短时…

超级实用的程序员接单平台,看完少走几年弯路,强推第一个!

”前途光明我看不见&#xff0c;道路曲折我走不完。“ 兜兜转转&#xff0c;心心念念&#xff0c;念念不忘&#xff0c;必有回响。终于找到了....... 网络上好多人都在推荐程序员线上接单&#xff0c;有人说赚得盆满钵满&#xff0c;有的人被坑得破口大骂&#xff0c;还有的人…

解决Zotero不显示标签的问题

目录 问题描述 解决办法&#xff1a; 问题描述 Zotero是一款学习助手&#xff0c;可以帮助我们梳理文献&#xff0c;方便我们整理。 最近电脑从windows换到mac&#xff0c;重新安装了Zotero&#xff0c;发现之前的一直设置都没有了。比如设置好的标签信息不显示了。如下图: …

matlab设置背景颜色

matlab默认的背景颜色是纯白RGB(255,255,255)&#xff0c;纯白太刺眼&#xff0c;看久了&#xff0c;眼睛会酸胀、疼痛&#xff0c;将其改成豆沙绿RGB(205,123,90)&#xff0c;或者给出浅绿色RGB(128,255,255), 颜色就会柔和很多&#xff0c;眼睛感觉更舒适。     下面介绍在…

Java使用x-www-form-urlencoded发请求

平常在开发过程中用的最多的就是JSON格式&#xff0c;请求编码就是 application/json&#xff0c;但偏偏有些接口是 x-www-form-urlencoded&#xff0c;怎么办呢&#xff0c;重新封装喽 在POSTMan工具是叫 x-www-form-urlencoded 在 APIpost工具中是叫 urlencoded Map<Str…

2023年【施工升降机司机(建筑特殊工种)】最新解析及施工升降机司机(建筑特殊工种)考试资料

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 施工升降机司机(建筑特殊工种)最新解析参考答案及施工升降机司机(建筑特殊工种)考试试题解析是安全生产模拟考试一点通题库老师及施工升降机司机(建筑特殊工种)操作证已考过的学员汇总&#xff0c;相对有效帮助施工升…

SMART PLC累计流量功能块(梯形积分法+浮点数累加精度控制)

S7-200SMART PLC数值积分器相关知识请参考下面文章链接: SMART PLC数值积分器功能块(矩形+梯形积分法完整源代码)-CSDN博客文章浏览阅读153次。PLC的数值积分器算法也可以参考下面文章链接:PLC算法系列之数值积分器(Integrator)-CSDN博客数值积分和微分在工程上的重要意义不…

C语言进阶之冒泡排序

✨ 猪巴戒&#xff1a;个人主页✨ 所属专栏&#xff1a;《C语言进阶》 &#x1f388;跟着猪巴戒&#xff0c;一起学习C语言&#x1f388; 目录 前情回顾 1、回调函数 2、冒泡排序 3、库函数qsort cmp&#xff08;sqort中的比较函数&#xff0c;需要我们自定义&#xff09; …

c++|内联函数

一、概念 以inline修饰的函数叫做内联函数&#xff0c;编译时c编译器会在调用函数的地方展开&#xff0c;而不会建立栈帧&#xff0c;提升了程序运行的效率 例子&#xff1a; #include <iostream> using namespace std;int Add(int left, int right) {return left - ri…

详解硬盘的接口、总线和协议

总线&#xff1a;总线是计算机系统中用于连接各个硬件组件的一种通信方式&#xff0c;它可以实现数据、地址和控制信号的传输。在服务器中&#xff0c;内部总线起着承载数据和控制信号的重要作用。总线在单位时间内能传输数据量称为带宽。分为SATA&#xff0c;SAS&#xff0c;P…

Deep Learning for Monocular Depth Estimation: A Review.基于深度学习的深度估计

传统的深度估计方法通常是使用双目相机&#xff0c;计算两个2D图像的视差&#xff0c;然后通过立体匹配和三角剖分得到深度图。然而&#xff0c;双目深度估计方法至少需要两个固定的摄像机&#xff0c;当场景的纹理较少或者没有纹理的时候&#xff0c;很难从图像中捕捉足够的特…
最新文章