Sentinel - 流量保护
字数: 0 字 时长: 0 分钟
简介
Sentinel 是一个开源的流控解决方案,它提供了多种流控规则:
- 流量控制规则
- 熔断降级规则
- 热点参数规则
- 来源访问规则
- 系统保护规则
架构图
环境搭建
- 引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
- 配置连接
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
异常处理
Sentinel 的异常处理机制,对于 web 接口资源的报错会由默认的 BlockExceptionHandler
处理,因此可以自定义一个 BlockExceptionHandler
来处理 web 异常
@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
指定的方法来处理异常
// 当发生异常时,由指定的兜底回调方法返回结果
@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)、请求频率、并发数等,来防止系统因为流量过大而出现性能问题或资源耗尽。
常见限流算法
- 计数限流
限制系统能同时处理的请求数量,保存计数器,每开始处理一个请求,计数器加 1 ;处理完毕之后计数器减一。计数器超过阈值就拒绝请求。
- 固定窗口限流
相比计数限流多了时间窗口的概念,计数器每过一个时间窗口就重置。
- 滑动窗口限流
固定窗口限流有临界问题:比如限流 QPS 为 100 ,在 0.8 秒涌入 100 个请求,在 1 秒重置计数器, 1.2 秒又涌入了 100 个请求(相当于 0.4 s内服务处理了 200 个请求,对于阈值为 100/s 的系统是无法接受的)。
于是引入滑动窗口限流解决这个问题:除了引入计数器外,还需要记录时间窗口内每个请求到达的时间点,保证滑动时间窗口内请求数不超过阈值。
- 漏桶算法
类似线程池的任务队列,超过阈值的请求放到队列排队。优点是面对突发流量也很平滑处理,但缺点也是面对突发请求,服务的处理速度和平时一样的
- 令牌桶算法
漏桶是请求定速地从桶内流出,令牌桶是定速地往桶内放入令牌,请求只能拿到了令牌才能通过
令牌桶在应对突发流量时,加入桶内已经有 100 个令牌,那么这个 100 个请求就可以立马拿到令牌开始处理,因此应对突发流量令牌桶表现更好
流控模式
流控效果
熔断降级
服务熔断指的是某个服务的调用失败率持续升高时,通过中断对该服务的请求,防止系统资源被不断消耗,进而保护整个系统不受影响。熔断机制的灵感来源于电路断路器。
服务降级指在系统压力过大或部分服务出现故障时,暂时减少或关闭某些不必要的功能,从而保证核心功能的正常运行,避免系统崩溃。
sentinel 断路器原理
熔断与兜底
热点参数
热点参数实现 秒杀
- 需求1:每个用户秒杀 QPS 不得超过 1 (秒杀下单 userId 级别)
- 需求2:6号用户是 VVIP,不限制 QPS
- 需求3:666号是下架商品,不允许访问
1. 自定义埋点
Sentinel 不支持 Web 资源进行热点规则配置,需要自定义埋点 (@SentinelResource
)
@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 号商品作为参数例外项