Sentinel - 流量保护
简介
Sentinel 是一个开源的流控解决方案,它提供了多种流控规则,如:
- 流量控制规则
- 熔断降级规则
- 热点参数规则
- 来源访问规则
- 系统保护规则
架构图
环境搭建
引入依赖
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
配置连接
yaml
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
异常处理
web 请求资源
Sentinel 的异常处理机制,对于 Web 接口资源的报错会由默认的
BlockExceptionHandler
处理 因此可以自定义一个BlockExceptionHandler
来处理 web 异常 当访问次数过多,返回给前端 429 错误码
java
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse
, String s, BlockException e) throws Exception {
httpServletResponse.setStatus(429);
PrintWriter writer = httpServletResponse.getWriter();
httpServletResponse.setContentType("application/json;charset=utf-8");
R error = R.error(s + " 被Sentinel限制了,原因: " + e.getClass());
String json = objectMapper.writeValueAsString(error);
writer.write(json);
writer.flush();
writer.close();
}
}
@SentinelResource
资源异常
最佳实践
使用 @SentinelResource 注解来处理非 Controller 的资源
被 @SentinelResource 注解的资源,当资源被 Sentinel 限制时,会调用 blockHandler 指定的方法
java
@GetMapping("/seckill")
@SentinelResource(value = "seckill-order",blockHandler = "seckillFallback")
public Order seckill(@RequestParam(value = "userId",defaultValue = "888") Long userId,
@RequestParam(value = "productId",defaultValue = "1000") Long productId
) {
Order order = orderService.createOrder(productId, userId);
order.setId(Long.MAX_VALUE);
return order;
}
public Order seckillFallback(Long userId, Long productId, BlockException e) {
System.out.println("seckill 兜底回调...");
Order order = new Order();
order.setId(productId);
order.setUserId(userId);
order.setAddress("异常信息: " + e.getClass());
return order;
}
流量控制
阈值类型
QPS : 每秒请求数 并发线程数 : 性能相对较低
流控模式
流控效果
熔断降级
断路器
工作原理
熔断与兜底
热点参数
案例:秒杀
- 需求1:每个用户秒杀 QPS 不得超过 1 (秒杀下单 userId 级别)
- 需求2:6号用户是 VVIP,不限制 QPS
- 需求3:666号是下架商品,不允许访问
自定义埋点
Sentinel 不支持 Web 资源进行热点规则配置,需要自定义埋点 (@SentinelResource)
java
@GetMapping("/seckill")
@SentinelResource(value = "seckill-order",blockHandler = "seckillFallback")
public Order seckill(@RequestParam(value = "userId",defaultValue = "888") Long userId,
@RequestParam(value = "productId",defaultValue = "1000") Long productId
) {
Order order = orderService.createOrder(productId, userId);
order.setId(Long.MAX_VALUE);
return order;
}
热点参数规则配置
新增热点规则,对于普通 userId QPS 为 1;对于 6 号 VVIP 用户作为参数例外项
同理,可以再新增一个热点规则,将 666 号商品作为参数例外项