Skip to content

Sentinel - 流量保护

字数: 0 字 时长: 0 分钟

简介

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

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

架构图

sentinel架构图.webp

环境搭建

  1. 引入依赖
xml
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  1. 配置连接
yaml
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080

异常处理

sentinel异常处理.webp

Sentinel 的异常处理机制,对于 web 接口资源的报错会由默认的 BlockExceptionHandler 处理,因此可以自定义一个 BlockExceptionHandler 来处理 web 异常

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); // 访问次数过多返回 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 来自定义埋点,当自定义埋点资源被 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) {
    Order order = new Order();
    order.setId(productId);
    order.setUserId(userId);
    order.setAddress("异常信息: " + e.getClass());
    return order;
}

服务限流

服务限流是一种流量控制策略,它通过限制每秒请求的数量(QPS)、请求频率、并发数等,来防止系统因为流量过大而出现性能问题或资源耗尽。

流量控制.webp

常见限流算法

  1. 计数限流

限制系统能同时处理的请求数量,保存计数器,每开始处理一个请求,计数器加 1 ;处理完毕之后计数器减一。计数器超过阈值就拒绝请求。

  1. 固定窗口限流

相比计数限流多了时间窗口的概念,计数器每过一个时间窗口就重置。

  1. 滑动窗口限流

固定窗口限流有临界问题:比如限流 QPS 为 100 ,在 0.8 秒涌入 100 个请求,在 1 秒重置计数器, 1.2 秒又涌入了 100 个请求(相当于 0.4 s内服务处理了 200 个请求,对于阈值为 100/s 的系统是无法接受的)。

于是引入滑动窗口限流解决这个问题:除了引入计数器外,还需要记录时间窗口内每个请求到达的时间点,保证滑动时间窗口内请求数不超过阈值。

  1. 漏桶算法

类似线程池的任务队列,超过阈值的请求放到队列排队。优点是面对突发流量也很平滑处理,但缺点也是面对突发请求,服务的处理速度和平时一样的

  1. 令牌桶算法

漏桶是请求定速地从桶内流出,令牌桶是定速地往桶内放入令牌,请求只能拿到了令牌才能通过

令牌桶在应对突发流量时,加入桶内已经有 100 个令牌,那么这个 100 个请求就可以立马拿到令牌开始处理,因此应对突发流量令牌桶表现更好

流控模式

流控模式.webp

流控效果

流控效果.webp

熔断降级

服务熔断指的是某个服务的调用失败率持续升高时,通过中断对该服务的请求,防止系统资源被不断消耗,进而保护整个系统不受影响。熔断机制的灵感来源于电路断路器。

服务降级指在系统压力过大或部分服务出现故障时,暂时减少或关闭某些不必要的功能,从而保证核心功能的正常运行,避免系统崩溃。

断路器.webp

sentinel 断路器原理

sentinel 断路器工作原理.webp

熔断与兜底

熔断与兜底.webp

热点参数

热点参数实现 秒杀

  • 需求1:每个用户秒杀 QPS 不得超过 1 (秒杀下单 userId 级别)
  • 需求2:6号用户是 VVIP,不限制 QPS
  • 需求3:666号是下架商品,不允许访问

1. 自定义埋点

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

2. 热点参数规则配置

新增热点规则

  • 对于普通 userId QPS 为 1;
  • 对于 6 号 VVIP 用户作为参数例外项
  • 同理,可以再新增一个热点规则,将 666 号商品作为参数例外项

热点规则限流.webp