六 熔断规则
1 介绍
熔断降级一般用于远程调用,其核心目标在于通过(当下游服务性能下降或故障时主动拒绝请求)、
切断不稳定调用(避免请求积压导致资源耗尽)以及
快速返回降级结果(阻止局部故障蔓延至整个系统),从而保障系统稳定性;
隔离故障防止雪崩效应
其最佳实践是在客户端(调用端)进行配置,因为熔断降级是保护自己的,在该服务调用其他服务时,若其他服务存在问题,则切断连接进行快速返回,其核心组件为
断路器
2 断路器
断路器模式通过模拟智能开关的转换,为分布式系统提供动态容错保护:在依赖服务(如服务B)稳定时,断路器保持
闭合-打开-半开状态,允许调用请求正常透传;
闭合状态
当检测到服务B出现故障(如错误率超阈值、响应超时或异常堆积)时,断路器立即跳闸进入,此时所有调用被快速拦截并返回预设降级结果(如默认值或错误提示),此时调用请求并没有到达B,避免请求积压导致调用端资源耗尽或故障扩散;
打开状态
经过熔断时长后,断路器进入试探性恢复,仅放行少量请求检测服务B是否修复,若成功则恢复闭合状态,否则延长熔断时间,形成“监测-熔断-恢复”的闭环机制,有效平衡系统可用性与稳定性
半开状态
3 断路器工作原理
请求流量进入时,会设置统计时长和最小请求数,在统计时长内发送请求数达到最小请求数之上后,开始进行统计之后的流量情况是否触发异常
慢调用比例:当慢请求超过设定的比例时,断路器状态变为打开。慢请求指:超过1秒(可设定的阈值)没有返回的请求
异常比例:统计时长内返回结果异常居多,超过设定的比例
异常数:统计时长内返回结果异常居多,超过设定的数额
触发异常断路器转变状态为打开状态,会设置熔断时长(断路器处于打开状态的时间),断路器打开后,A不再发送请求给B,直接返回快速失败,熔断时间过后,断路器处于半开状态,
断路器半开状态收到请求调用会先放行一个请求进行探测,成功则变为闭合状态,失败则变为打开状态,再次等待熔断时间结束后,转为半开状态,依次循环

4 设置熔断规则 – 慢调用比例
为防止商品服务宕机从而对订单服务造成影响,可在订单中配置对商品的熔断规则

5 设置远程调用休眠时间并测试 – ProductController
@RestController
public class ProductController {
@Autowired
ProductService productService;
// 根据ID获取商品数据
@GetMapping("/product/{id}")
public Product getProduct(@PathVariable("id") Long productId,
HttpServletRequest request) {
// 获取请求头中 TokenA 的信息
String tokenA = request.getHeader("TokenA");
System.out.println("welcome TokenA:"+ tokenA);
Product product=productService.getProductById(productId);
// 休眠 2 秒
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return product;
}
}
快速刷新并观察控制台,根据熔断规则前5个请求返回虽然慢但是有数据返回(休眠2秒),多次刷新触发熔断后,熔断时间内返回变快(不再调用,直接快速失败)
![图片[1] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/23a2261f93384bbea1ee52da8ef5fea9.png)
![图片[2] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/c86ac87b3f1e412bbb4614c5ce1620c6.png)
![图片[3] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/4322c78676c441c9bb952e61207b6fd4.png)
![图片[4] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/6e8ad287ec544a33a1932d1b364d1d76.png)
经过熔断时间后,转为半开状态,可以再次发送请求,但此时只能通过少量请求,当请求成功且20秒内(半开等待期也叫冷却期,冷却期通常与熔断时间相同)无其他失败请求,恢复为闭合状态,若再次发送大量请求,则断路器再次转为打开状态,触发兜底回调
![图片[5] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/49f83d44e0174c8f9c0abf8b21a95346.png)

6 设置熔断规则 – 异常比例
① 编写业务异常 – ProductController
@RestController
public class ProductController {
@Autowired
ProductService productService;
// 根据ID获取商品数据
@GetMapping("/product/{id}")
public Product getProduct(@PathVariable("id") Long productId,
HttpServletRequest request) {
// 获取请求头中 TokenA 的信息
String tokenA = request.getHeader("TokenA");
System.out.println("welcome TokenA:"+ tokenA);
Product product=productService.getProductById(productId);
// 异常
int i=6/0;
// 休眠 2 秒
// try {
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
return product;
}
}
② 发送远程调用,返回状态码为500,触发兜底回调,此流程是将请求发送给远程后,远程产生异常返回,触发兜底回调(无熔断规则)
![图片[6] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/1687a0d0b0ba4d339255ed410c6edd17.png)
![图片[7] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/6ff8ba34478f4d03b53058a38b491a82.png)
③ 有熔断规则后,当远程出现问题,熔断时间内,不会再发送请求到远程,直接兜底回调,节约资源
![图片[8] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/de442983364b459bbed89fab0c585a78.png)
④ 快速刷新触发熔断,订单控制台不再发送请求,直接进行兜底回调,商品服务不会接收到请求,业务异常没有请求进行触发,控制台无输出
![图片[9] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/b3b6deca4bc24360b31363b297aa7b9a.png)

7 设置熔断规则 – 异常数
① 设置异常数
![图片[10] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/922a3e5103414d749c140df06e94926e.png)
② 测试
![图片[11] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/62bf4b4c48ac4ba0ac86f3af92fb713f.png)

七 热点规则
1 介绍
热点规则是流量控制的一种特殊形式,它能够在资源级别流控的基础上,进一步针对资源调用时携带的特定参数进行精细化限流,从而更有效地防护高频热点数据对系统造成的冲击。
热点规则用于统计和限制经常被访问的数据,例如商品 ID、用户 ID 等。通过热点规则,可以统计一段时间内某些参数的访问频次,并对这些高频访问的参数进行限流,以防止系统因局部热点而崩溃。
在 Web 应用中,热点规则需要埋点是因为 Web 请求的多样性和动态性导致参数位置、类型不固定,而 Sentinel 需通过埋点显式绑定资源名、精准提取并标准化监控参数,才能基于“资源+参数值”实现高频热点数据的精细化限流。
2 进行自定义埋点测试
① 取消之前设置的异常 – ProductController
@RestController
public class ProductController {
@Autowired
ProductService productService;
// 根据ID获取商品数据
@GetMapping("/product/{id}")
public Product getProduct(@PathVariable("id") Long productId,
HttpServletRequest request) {
// 获取请求头中 TokenA 的信息
String tokenA = request.getHeader("TokenA");
System.out.println("welcome TokenA:"+ tokenA);
Product product=productService.getProductById(productId);
// 业务异常
// int i=6/0;
// 休眠 2 秒
// try {
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
return product;
}
}
② 进行埋点 – OrderController
@Slf4j
@RestController
public class OrderController {
@Autowired
OrderService orderService;
// 所需属性
@Autowired
OrderProperties orderProperties;
@GetMapping("/config")
public String config(){
return "order.timeout:"+orderProperties.getTimeOut()
+ ";order.autoconfirm:"+orderProperties.getAutoConfirm()
+ ";order.dbUrl:"+orderProperties.getDbUrl();
}
@GetMapping("/create")
public Order createOrder(@RequestParam("productId") Long productId,
@RequestParam("userId") Long userId) {
Order order = orderService.createOrder(productId, userId);
return order;
}
// 自定义资源埋点并设置兜底回调方法
// fallback:处理业务异常(回调方法需要参数Throwable)。
// blockHandler:处理流控异常(回调方法需要参数BlockException)。
@GetMapping("/createB")
@SentinelResource(value = "createOrderB-Order",fallback = "createOrderBFallback")
public Order createOrderB(@RequestParam("productId") Long productId,
@RequestParam("userId") Long userId) {
Order order = orderService.createOrder(productId, userId);
order.setId(9999l);
return order;
}
// 兜底回调方法
public Order createOrderBFallback(Long productId, Long userId, Throwable exception) {
System.out.println("兜底回调啦");
// 无需创建订单 返回兜底订单数据即可
Order order = new Order();
order.setId(productId);
order.setUserId(userId);
order.setNickname("某人");
order.setAddress("异常信息"+exception.getClass());
return order;
}
@GetMapping("/dbInsert")
public String insert() {
return "Insert OK";
}
@GetMapping("/dbQuery")
public String query() {
log.info("寻寻觅觅");
return "Query OK";
}
}
③ 设置热点参数规则,方法会传递2个参数,参数索引
createOrderB,对应第
0个参数
1
![图片[12] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/c6e368552c7e40f286f471c48eb61145.png)
④ 快速刷新测试,出现流控异常,无论商品ID为何值
![图片[13] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/0b1e23821d8b43fd97b16b9d740f9351.png)
![图片[14] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/5e23c3c172a842dd951d2275e83fb6b0.png)
⑤ 更新方法,为该参数设置默认值 – OrderController
// 自定义资源埋点并设置兜底回调方法 设置方法参数自带默认值 从而不在路径中传递
@GetMapping("/createB")
@SentinelResource(value = "createOrderB-Order",fallback = "createOrderBFallback")
public Order createOrderB(@RequestParam(value = "productId",defaultValue = "4399") Long productId,
@RequestParam(value = "userId",defaultValue = "3366") Long userId) {
Order order = orderService.createOrder(productId, userId);
order.setId(9999l);
return order;
}
⑥ 设置规则(规则同上),进行测试,发现由于默认值存在,仍会进行流控
![图片[15] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/49d688e24aca49d29c0b29e20620fef5.png)
⑦ 更新方法,该参数可以不带 – OrderController
// 自定义资源埋点并设置兜底回调方法 设置方法参数自带默认值 从而不在路径中传递
@GetMapping("/createB")
@SentinelResource(value = "createOrderB-Order",fallback = "createOrderBFallback")
public Order createOrderB(@RequestParam(value = "productId",required = false) Long productId,
@RequestParam(value = "userId",required = false) Long userId) {
Order order = orderService.createOrder(productId, userId);
order.setId(9999l);
return order;
}
⑧ 设置规则(规则同上),进行测试,发现由于没有携带该参数,不会进行流控

3 高级选项 – 设置例外项
① 设置规则
![图片[16] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/0c1f5be4c17248c1a0555dd85912b9da.png)
![图片[17] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/7e1e1fdc0c14434d8a800874d80ff91c.png)
② 测试,此时商品id为666的订单不会被限流,其他的id会被限流
![图片[18] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/97b40c498ade4d8291d4782b5e63703f.png)

4 第二个参数设置 – 针对ID不可访问
① 建立规则,第二个参数需要再建立一个规则
![图片[19] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/a4b8a1245eca4148a308a45e17679c4e.png)
② 设立针对ID,该ID不可访问
![图片[20] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/8943dc87948646c997673fecd11c2fed.png)
③ 测试发现,用户id为365则不可访问,即使另一个参数为例外项也不行
![图片[21] - Java研学-SpringCloud(十一) - 宋马](https://pic.songma.com/blogimg/20251001/98957f63f8314a008579b7c3fb5b23d7.png)




















暂无评论内容