当前位置: 首页 > news >正文

SpringCloud Alibaba Sentinel 流量治理、熔断限流(四)

目录

一 概念引入

二 运作流程

三 使用

四 异常处理

1 拦截器全局兜底

2 指定资源方法兜底 blockHandler/fallbcak

3 远程调用的兜底 Fallback

4 sphu硬编码

五 几种常用的控制规则

1 流控规则

2 熔断规则

3 热点规则

4 授权规则

5 系统规则


一 概念引入

二 运作流程

三 使用

下载对应的jar包:

java -jar sentinel-dashboard-1.8.8.jar

Release v1.8.8 · alibaba/Sentinel

这里的默认端口是8080,最好与本地的启动端口进行区分

默认账号密码均为sentinel

在本地项目当中进行相对应的配置

spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true

重新启动项目展示:

四 异常处理

核心优先级总结

  1. 优先执行方法级别的兜底(blockHandler

  2. 如果方法没有兜底,才会进入 全局 BlockExceptionHandler

  3. 如果既没有 @SentinelResource,也没有全局拦截器,那么异常会直接抛到调用方(用户就看到 500 错误页了 )。

三个层级:

1 拦截器全局兜底

代码定义:@SentinelResource注解

    @SentinelResource("createOrder")@Overridepublic Order createOrder(Long productId, Long userId) {// Product product = getProductFromRemote3(productId);Product product = productFeignClient.getProductById(productId);Order order = new Order();order.setId(1L);// 远程调用计算商品数额order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickName("张三");order.setAddress("青岛");// 远程调用获取商品信息order.setProductList(Arrays.asList(product));return order;}

控制台:进行限流

页面展示:限流结束

拦截器:自定义拦截器的返回规则

package com.ax.order.exception;import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.ax.common.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;import java.io.PrintWriter;@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {private final ObjectMapper objectMapper = new ObjectMapper();@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,String s, BlockException e) throws Exception {httpServletResponse.setContentType("application/json;charset=utf-8");PrintWriter writer = httpServletResponse.getWriter();R error = R.error(500, s + "被Sentinel 给限流了" + e.getClass());String s1 = objectMapper.writeValueAsString(error);writer.write(s1);writer.flush();}
}

效果展示:

2 指定资源方法兜底 blockHandler/fallbcak

代码实现:

    // sentinel有两种情况,正常则返回,异常则调用blockHandler指定的方法@SentinelResource(value = "createOrder", blockHandler = "createOrderFallback")@Overridepublic Order createOrder(Long productId, Long userId) {// Product product = getProductFromRemote3(productId);Product product = productFeignClient.getProductById(productId);Order order = new Order();order.setId(1L);// 远程调用计算商品数额order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickName("张三");order.setAddress("青岛");// 远程调用获取商品信息order.setProductList(Arrays.asList(product));return order;}//兜底回调public Order createOrderFallback(Long productId, Long userId, BlockException e) {Order order = new Order();order.setId(1L);order.setTotalAmount(new BigDecimal(0));order.setUserId(userId);order.setNickName("未知用户");order.setAddress("异常信息" + e.getMessage());order.setProductList(null);return order;}
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;import java.math.BigDecimal;
import java.util.Arrays;@Service
public class OrderServiceImpl implements OrderService {@SentinelResource(value = "createOrder",blockHandler = "createOrderBlockHandler",  // 限流、熔断时走这里fallback = "createOrderFallback"           // 业务异常时走这里)@Overridepublic Order createOrder(Long productId, Long userId) {// 模拟远程调用商品服务Product product = productFeignClient.getProductById(productId);// 模拟异常(比如商品服务挂了)if (product == null) {throw new RuntimeException("商品不存在或服务不可用");}Order order = new Order();order.setId(1L);order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickName("张三");order.setAddress("青岛");order.setProductList(Arrays.asList(product));return order;}/*** blockHandler: 处理 Sentinel 限流/熔断/系统保护* 触发条件:流量超限、熔断等情况*/public Order createOrderBlockHandler(Long productId, Long userId, BlockException e) {Order order = new Order();order.setId(-1L);order.setTotalAmount(BigDecimal.ZERO);order.setUserId(userId);order.setNickName("系统繁忙");order.setAddress("触发流控/熔断:" + e.getClass().getSimpleName());order.setProductList(null);return order;}/*** fallback: 处理业务异常(运行时异常)* 触发条件:代码运行报错,如空指针、远程调用异常*/public Order createOrderFallback(Long productId, Long userId, Throwable e) {Order order = new Order();order.setId(-2L);order.setTotalAmount(BigDecimal.ZERO);order.setUserId(userId);order.setNickName("未知用户");order.setAddress("业务异常兜底:" + e.getMessage());order.setProductList(null);return order;}
}

1 如果是流量过大 / 系统保护(Sentinel 规则触发) → blockHandler

例子:秒杀活动、热点参数限流。

作用:告诉用户“当前排队人数过多,请稍后再试”。

2 如果是业务逻辑异常fallback

例子:远程调用下游服务失败(商品服务挂了)、数据处理出现异常。

作用:返回一个默认结果或缓存数据,保证系统可用性。

3 两者可以配合使用

blockHandler → 处理 限流/熔断

fallback → 处理 业务异常

Sentinel 会优先调用 blockHandler,如果没有配置,再进入 fallback

3 远程调用的兜底 Fallback

package com.ax.order.feign;import com.ax.order.feign.fallback.ProductFeignClientFallback;
import com.ax.product.bean.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "service-product", fallback = ProductFeignClientFallback.class)
public interface ProductFeignClient {/*** 测试FeignClient** @param id*///mvc注解两套使用逻辑//标注在Controller上,为接收请求//标注在FeignClient上,为发送请求@GetMapping("/product/{id}")Product getProductById(@PathVariable("id") Long id);//如果调用自己其他服务的api直接将其方法复制过来即可,下面这个就是从product当中复制过来的//    @GetMapping("/product/{id}")//    Product getProduct(@PathVariable("id") Long id);
}

回调:

package com.ax.order.feign.fallback;import com.ax.order.feign.ProductFeignClient;
import com.ax.product.bean.Product;
import org.springframework.stereotype.Component;import java.math.BigDecimal;@Component
public class ProductFeignClientFallback implements ProductFeignClient {@Overridepublic Product getProductById(Long id) {System.out.println("兜底回调");Product product = new Product();product.setId(id);product.setProductName("商品不存在");product.setNum(0);product.setPrice(new BigDecimal("0.0"));return product;}
}

4 sphu硬编码

这个硬编码方式就是使用 SphU.entry() 来定义一个资源,配合 try-with-resources 或者 try-catch-finally 来做 限流、熔断、降级 控制。

五 几种常用的控制规则

1 流控规则

单机模式

流控规则:限制多余请求,从而保护系统资源不被耗尽。

资源名:标识限流规则的目标对象。

针对来源:看可以对不同来源设置不同的规则。

阈值类型:单机维度:QPS指的是秒请求数。并发线程数指的是秒请求线程数。

流控模式:触发条件

1 直接:对当前资源本身进行限流。2 关联:不仅受到当前资源的影响,如果当前资源下的调用消耗也大,将会将当前资源进行限流。3 链路:只对特定调用链路中的资源进行限流。

流控效果:超限之后如何处理

1 快速失败:直接返回异常 2 预热模式:防止项目的冷启动(项目启动后会慢慢的提升,不会直接到预定值,而是在指定时间内达到) 3 排队等待:超过阈值的进入等待队列,按照顺序依次排队执行。  

关联:给readDb加流控,关联资源是writeDb,表面上是对readDb加流量管控,但是其大量请求并没有影响,影响的前提是writeDb的请求较大,那么就会将readDb进行限制

链路:(比如一个方法被多个地方引用,可以指定其具体的一个链路,比如说秒杀与退货,两个都有对数据库当中数据查询,那么就可以指定秒杀的链路进行流控)

集群模式

集群阈值模式:1 单机均摊:配置的阈值会按照机器数量平分到每台机器。2 总体阈值:阈值是所有的机器总和。

失败退化:当 Token Server 不可用时,是否自动退化为 单机限流。

上下文统一

  • web-context-unify: 主要用于 是否启用统一的 Web 上下文处理

  • 如果设置为 true

    • 系统会对所有的 HTTP 响应做统一封装(比如统一响应格式、统一异常处理)。

    • 方便前端统一处理接口返回数据和错误码。

  • 如果设置为 false

    • 不做统一封装,接口返回什么就原样返回。

    • 适合需要原始返回结构或者第三方接口调用的场景

2 熔断规则

核心作用:熔断降级作为保护自身的手段,通常在客户端进行配置,便于更好的获得数据或者执行业务。

1 切断不稳定调用:通过持续监控下游服务的调用指标(如异常比例、响应时长),当故障超过预设阈值时,熔断器将自动开启,立即切断所有请求,防止问题蔓延。

2 快速返回不积压:熔断开启后,所有后续请求不再尝试访问故障服务,而是在本地即刻返回失败响应。此举能有效避免请求线程阻塞和资源堆积,保护调用方自身资源不被耗尽。

3 避免雪崩:将故障服务隔离在调用链之外,将其影响范围限制在局部,有效阻止了单个后端的故障向上蔓延,从而保障整个分布式系统的稳定性和高可用性,避免系统性崩溃。

断路器

工作原理

三个状态:关闭,半开,打开

这个状态机模型实现了一个全自动的、智能的故障隔离与恢复循环

  1. 正常期:(Closed) 监控流量,一切正常。

  2. 故障检测:监控指标超标 -> 触发熔断 -> (Open) 快速失败,保护系统。

  3. 恢复试探:熔断时间到 -> (Half-Open) 放行探测请求。

  4. 恢复成功:探测成功 -> 回到 (Closed) 状态,系统恢复正常。

  5. 恢复失败:探测失败 -> 回到 (Open) 状态,继续熔断。

三个参数:慢调用比例,异常比例,异常数

慢调用比例:

最大RT:相当于响应时间,超过则为慢请求。1000ms

比例阈值:超过多少比例的请求为慢请求的条件。0-1

熔断时长:熔断时长。1s

最小请求数:达到一定的数量级才可以满足。

异常比例:

比例阈值:调用出现异常的比例。0-1

熔断时长:熔断时长。1s

最小请求数:达到一定数量级才可以满足。

异常数

异常数:出现异常的数量

熔断时长:熔断时长。1s

最小请求数:达到一定数量级才可以满足。

3 热点规则

热点规则:在原有的流控的基础之上,可以实现更加精细化的流量控制,不是对某个资源的一刀切,而是智能的识别出“热点参数”并对其实施特殊关照(限流操作,可以结合前面的兜底处理)。

展示:注意required=false的使用

4 授权规则

5 系统规则

http://www.xdnf.cn/news/1400851.html

相关文章:

  • (三)Python语法基础(实战)
  • 为什么要用 Markdown?以及如何使用它
  • 【系列09】端侧AI:构建与部署高效的本地化AI模型 第8章:移动端部署实战 - Android
  • SQLSugar 封装原理详解:从架构到核心模块的底层实现
  • C++ 面试高频考点 力扣 34. 在排序数组中查找元素的第一个和最后一个位置 二分查找左右端点 题解 每日一题
  • PostgreSQL表空间(Tablespace)作用(管理数据库对象的存储位置)(pg_default、pg_global)
  • 一道比较难的sql题,筛选出重复字段的行数
  • 【物联网】bleak (scan)扫描在干什么? BLE 广播(Advertising)
  • jxWebUI--下拉选择框
  • AtCoder Beginner Contest 421
  • 海盗王64位dx9客户端修改篇之三
  • React前端开发_Day10
  • 骑行商城怎么开发
  • 【PCIE系列】1---PCIE系统拓扑结构分析
  • Ethan独立开发新品速递 | 2025-08-30
  • Libvio 访问异常排查关键要点
  • 基于Ultralytics YOLO通用目标检测训练体系与PyTorch EfficientNet的图像分类体系实现
  • oha:一款轻量级HTTP负载测试工具
  • 流式HTTP MCP服务器开发
  • ceph集群部署
  • 接雨水,leetCode热题100,C++实现
  • 嵌入式linux相机(2)
  • PostgreSQL数据类型一览(数值类型)
  • opencv实现轮廓绘制和选择
  • 生成式 AI 重构内容生产:效率提升背后的创作版权边界争议
  • day43-Ansible-PlayBook
  • 如何使用快照将 AWS OpenSearch 服务中的数据从开发环境复制到生产环境
  • 知料觅得-新一代AI搜索引擎
  • Linux网络服务发现在VPS云服务器自动化配置的关键技术与实践
  • 给某个conda环境安装CUDA 12.4版本 全局CUDA不变