Skip to content

Sentinel - 流量保护

简介

Sentinel官网链接

Sentinel 是一个开源的流控解决方案,它提供了多种流控规则,如:

  • 流量控制规则
  • 熔断降级规则
  • 热点参数规则
  • 来源访问规则
  • 系统保护规则

架构图

sentinel架构图.png

环境搭建

引入依赖

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

配置连接

yaml
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080

异常处理

sentinel异常处理.png

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;
    }

流量控制

流量控制.png

阈值类型

QPS : 每秒请求数 并发线程数 : 性能相对较低

流控模式

流控模式.png

流控效果

流控效果.png

熔断降级

断路器

断路器.png

工作原理

sentinel 断路器工作原理.png

熔断与兜底

熔断与兜底.png

热点参数

案例:秒杀

  • 需求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 号商品作为参数例外项

热点规则限流.png